diff --git a/.gitignore b/.gitignore index f35f8a89f..645314338 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ __pycache__/ # C extensions *.so /backend/graph +/nrcmvp/ # Distribution / packaging .Python build/ diff --git a/SEARCH_FEATURE_README.md b/SEARCH_FEATURE_README.md new file mode 100644 index 000000000..142e1c808 --- /dev/null +++ b/SEARCH_FEATURE_README.md @@ -0,0 +1,329 @@ +# Graph Search Feature - Implementation Guide + +## Overview + +This document describes the implementation of a robust graph search functionality that allows users to search for nodes across all documents in the Neo4j database and extract subgraphs with configurable depth. + +## Features Implemented + +### 1. Backend Search API +- **Node Search**: Search for nodes across all documents by name, description, title, or ID +- **Subgraph Extraction**: Extract subgraphs from specific nodes with configurable depth +- **Combined Search**: Search and extract subgraphs in one operation +- **Configurable Parameters**: Node type, depth, max results, max nodes + +### 2. Frontend Search Interface +- **Search Panel**: User-friendly interface for configuring search parameters +- **Search Results**: Display search results with node information and subgraph statistics +- **Graph Visualization**: Interactive visualization of extracted subgraphs +- **Real-time Feedback**: Loading states, error handling, and progress indicators + +## API Endpoints + +### 1. `/search_nodes` +Search for nodes across all documents. + +**Parameters:** +- `search_term` (required): The search term to look for +- `node_type` (optional, default: "Person"): Type of node to search for +- `max_results` (optional, default: 50): Maximum number of results to return +- Connection parameters: `uri`, `userName`, `password`, `database` + +**Response:** +```json +{ + "search_term": "john", + "node_type": "Person", + "total_results": 5, + "nodes": [ + { + "element_id": "4:1234:5678", + "labels": ["Person", "__Entity__"], + "properties": { + "name": "John Smith", + "description": "Software Engineer" + } + } + ] +} +``` + +### 2. `/get_subgraph` +Extract a subgraph from a specific node. + +**Parameters:** +- `node_id` (required): The element ID of the starting node +- `depth` (optional, default: 4): Maximum depth of the subgraph +- `max_nodes` (optional, default: 1000): Maximum number of nodes to include +- Connection parameters: `uri`, `userName`, `password`, `database` + +**Response:** +```json +{ + "start_node_id": "4:1234:5678", + "depth": 4, + "nodes": [...], + "relationships": [...] +} +``` + +### 3. `/search_and_get_subgraph` +Combined search and subgraph extraction. + +**Parameters:** +- `search_term` (required): The search term to look for +- `node_type` (optional, default: "Person"): Type of node to search for +- `depth` (optional, default: 4): Maximum depth of the subgraph +- `max_results` (optional, default: 10): Maximum number of search results to process +- Connection parameters: `uri`, `userName`, `password`, `database` + +**Response:** +```json +{ + "search_term": "john", + "node_type": "Person", + "total_results": 5, + "subgraphs": [ + { + "start_node_id": "4:1234:5678", + "depth": 4, + "nodes": [...], + "relationships": [...], + "matching_node": {...} + } + ] +} +``` + +## Implementation Details + +### Backend Implementation + +#### 1. Graph Query Functions (`backend/src/graph_query.py`) + +**`search_nodes()`**: Searches for nodes using Cypher queries +```python +def search_nodes(uri, username, password, database, search_term, node_type="Person", max_results=50): + # Searches across multiple properties: name, description, title, id + # Returns processed nodes with element_id, labels, and properties +``` + +**`get_subgraph_from_node()`**: Extracts subgraphs with configurable depth +```python +def get_subgraph_from_node(uri, username, password, database, node_id, depth=4, max_nodes=1000): + # Uses variable-length path queries to extract subgraphs + # Processes nodes and relationships for frontend consumption +``` + +**`search_and_get_subgraph()`**: Combines search and subgraph extraction +```python +def search_and_get_subgraph(uri, username, password, database, search_term, node_type="Person", depth=4, max_results=10): + # First searches for nodes, then extracts subgraphs for each match + # Returns comprehensive results with metadata +``` + +#### 2. API Endpoints (`backend/score.py`) + +Three new FastAPI endpoints with comprehensive error handling, logging, and performance monitoring. + +#### 3. Main Functions (`backend/src/main.py`) + +API wrapper functions that integrate with the existing codebase patterns. + +### Frontend Implementation + +#### 1. Search Services (`frontend-graph/src/services/GraphQuery.ts`) + +Three new API service functions with proper error handling and timeout management. + +#### 2. Search Components + +**`SearchPanel.tsx`**: User interface for configuring search parameters +- Search term input +- Node type selection +- Depth configuration +- Max results selection +- Connection status display + +**`SearchResults.tsx`**: Display search results and subgraph information +- Search summary +- Result cards with node information +- Subgraph statistics +- View subgraph buttons + +#### 3. Integration (`GraphViewer.tsx`) + +Updated main component to integrate search functionality with existing graph visualization. + +## Usage Examples + +### 1. Search for People +```typescript +// Search for people named "John" +const searchParams = { + search_term: "John", + node_type: "Person", + depth: 4, + max_results: 10 +}; + +const response = await searchAndGetSubgraphAPI( + searchParams.search_term, + searchParams.node_type, + searchParams.depth, + searchParams.max_results, + abortController.signal, + connectionParams +); +``` + +### 2. Extract Subgraph from Node +```typescript +// Extract subgraph from a specific node +const response = await getSubgraphAPI( + "4:1234:5678", // node_id + 3, // depth + 500, // max_nodes + abortController.signal, + connectionParams +); +``` + +### 3. Search Organizations +```typescript +// Search for organizations +const searchParams = { + search_term: "Microsoft", + node_type: "Organization", + depth: 3, + max_results: 5 +}; +``` + +## Performance Considerations + +### 1. Query Optimization +- Uses indexed properties for search (name, description, title, id) +- Configurable result limits to prevent large result sets +- Efficient subgraph extraction with depth limits + +### 2. Frontend Performance +- Debounced search inputs +- AbortController for request cancellation +- Progressive loading for large subgraphs +- Memory management for graph visualization + +### 3. Backend Performance +- Connection pooling and reuse +- Batch processing for multiple subgraphs +- Comprehensive logging and monitoring +- Error handling and recovery + +## Security Features + +### 1. Input Validation +- Search term sanitization +- Parameter validation and limits +- SQL injection prevention through parameterized queries + +### 2. Access Control +- Connection parameter validation +- Database access controls +- Error message sanitization + +## Testing + +### 1. Backend Testing +Run the test script to verify functionality: +```bash +cd backend +python test_search.py +``` + +### 2. Frontend Testing +- Test search functionality with various parameters +- Verify subgraph visualization +- Test error handling and edge cases + +## Configuration + +### 1. Environment Variables +```bash +NEO4J_URI=neo4j+ssc://your-database.neo4j.io +NEO4J_USERNAME=neo4j +NEO4J_PASSWORD=your-password +NEO4J_DATABASE=neo4j +``` + +### 2. Search Parameters +- **Default Node Type**: Person +- **Default Depth**: 4 levels +- **Default Max Results**: 10 for combined search, 50 for node search +- **Default Max Nodes**: 1000 for subgraph extraction + +## Error Handling + +### 1. Backend Errors +- Connection failures +- Query timeouts +- Invalid parameters +- Database errors + +### 2. Frontend Errors +- Network timeouts +- API errors +- Invalid search parameters +- Graph rendering errors + +## Future Enhancements + +### 1. Advanced Search +- Fuzzy search capabilities +- Semantic search using embeddings +- Multi-property search with weights +- Search across multiple node types + +### 2. Performance Improvements +- Search result caching +- Incremental subgraph loading +- Background search processing +- Search result pagination + +### 3. User Experience +- Search history +- Saved searches +- Search suggestions +- Advanced filtering options + +## Troubleshooting + +### Common Issues + +1. **No search results** + - Verify node types exist in the database + - Check search term spelling + - Ensure proper connection parameters + +2. **Large subgraphs** + - Reduce depth parameter + - Lower max_nodes limit + - Use more specific search terms + +3. **Performance issues** + - Check database indexes + - Monitor query execution time + - Adjust result limits + +### Debug Information + +Enable debug logging to troubleshoot issues: +```python +import logging +logging.basicConfig(level=logging.DEBUG) +``` + +## Conclusion + +The graph search feature provides a robust, scalable solution for searching and visualizing knowledge graphs. The implementation follows best practices for performance, security, and user experience, making it suitable for production use. + +The modular design allows for easy extension and customization, while the comprehensive error handling ensures reliable operation in various environments. diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 000000000..6473115d8 --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,80 @@ +# Makefile for PostgreSQL monitoring database operations + +.PHONY: help install migrate rollback reset seed clean test + +# Default target +help: + @echo "Available commands:" + @echo " install - Install Python dependencies" + @echo " migrate - Run database migrations" + @echo " rollback - Rollback last migration" + @echo " reset - Reset database (drop all tables and recreate)" + @echo " seed - Seed database with sample data" + @echo " clean - Clean up temporary files" + @echo " test - Test database connection" + @echo " status - Show migration status" + +# Install dependencies +install: + pip3 install -r requirements.txt + +# Initialize Alembic (first time only) +init-alembic: + alembic init migrations + +# Run all pending migrations +migrate: + @echo "Running database migrations..." + alembic upgrade head + @echo "Migrations completed!" + +# Rollback last migration +rollback: + @echo "Rolling back last migration..." + alembic downgrade -1 + @echo "Rollback completed!" + +# Reset database (drop all and recreate) +reset: + @echo "Resetting database..." + alembic downgrade base + alembic upgrade head + @echo "Database reset completed!" + +# Show migration status +status: + @echo "Migration status:" + alembic current + alembic history + +# Seed database with sample data +seed: + @echo "Seeding database with sample data..." + python3 -c "from src.database import get_db; from src.monitoring_service_pg import MonitoringServicePG; db = get_db(); service = MonitoringServicePG(); sample_entities = [{'name': 'Bill Gates', 'type': 'Individual', 'risk_threshold': 0.7, 'category': 'Technology', 'status': 'active'}, {'name': 'Microsoft', 'type': 'Organization', 'risk_threshold': 0.6, 'category': 'Technology', 'status': 'active'}, {'name': 'OpenAI', 'type': 'Organization', 'risk_threshold': 0.8, 'category': 'AI', 'status': 'active'}]; [print(f'Added entity: {entity[\"name\"]}') if service.store_monitored_entity(entity) else print(f'Failed to add {entity[\"name\"]}') for entity in sample_entities]; print('Database seeding completed!')" + +# Test database connection +test: + @echo "Testing database connection..." + python3 -c "from src.database import get_db; db = get_db(); result = db.execute_query('SELECT 1 as test'); print(f'Database connection successful! Test result: {result}')" + +# Clean up temporary files +clean: + find . -type f -name "*.pyc" -delete + find . -type d -name "__pycache__" -delete + find . -type f -name "*.log" -delete + @echo "Cleanup completed!" + +# Create new migration +migration: + @read -p "Enter migration name: " name; \ + alembic revision --autogenerate -m "$$name" + +# Show database tables +tables: + @echo "Database tables:" + python3 -c "from src.database import get_db; db = get_db(); result = db.execute_query(\"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name\"); [print(f' - {row[\"table_name\"]}') for row in result]" + +# Show table structure +schema: + @echo "Table schemas:" + python3 -c "from src.database import get_db; db = get_db(); tables = ['monitored_entities', 'risk_assessments', 'alerts']; [print(f'\\n{table}:') or [print(f' {row[\"column_name\"]:<20} {row[\"data_type\"]:<15} {\"NULL\" if row[\"is_nullable\"] == \"YES\" else \"NOT NULL\"}') for row in db.execute_query(f\"SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = '{table}' ORDER BY ordinal_position\")] for table in tables]" diff --git a/backend/README.md b/backend/README.md index 1ab091216..b20716a5c 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,12 +1,14 @@ # Project Overview + Welcome to our project! This project is built using FastAPI framework to create a fast and modern API with Python. ## Feature + API Endpoint : This project provides various API endpoint to perform specific tasks. Data Validation : Utilize FastAPI data validation and serialization feature. Interactive Documentation : Access Swagger UI and ReDoc for interactive API documentation. -## Getting Started +## Getting Started Follow these steps to set up and run the project locally: @@ -20,32 +22,40 @@ Follow these steps to set up and run the project locally: > pip install -t requirements.txt -## Run backend project using unicorn +## Run backend project using uvicorn + Run the server: + > uvicorn score:app --reload ## Run project using docker -## prerequisite + +## prerequisite + Before proceeding, ensure the following software is installed on your machine Docker: https://www.docker.com/ 1. Build the docker image + > docker build -t your_image_name . - + Replace `your_image_name` with the meaningful name for your Docker image 2. Run the Docker Container + > docker run -it -p 8000:8000 your_image_name - + Replace `8000` with the desired port. ## Access the API Documentation + Open your browser and navigate to http://127.0.0.1:8000/docs for Swagger UI or http://127.0.0.1:8000/redocs for ReDoc. ## Project Structure + `score.py`: Score entry point for FastAPI application ## Configuration @@ -66,6 +76,6 @@ Update the environment variable in `.env` file. Refer example.env in backend fol `AWS_SECRET_ACCESS_KEY` : AWS secret access key - ## Contact + For questions or support, feel free to contact us at christopher.crosbie@neo4j.com or michael.hunger@neo4j.com diff --git a/backend/alembic.ini b/backend/alembic.ini new file mode 100644 index 000000000..bd87409d6 --- /dev/null +++ b/backend/alembic.ini @@ -0,0 +1,106 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = migrations + +# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s +# Uncomment the line below if you want the files to be prepended with date and time +# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s + +# sys.path path, will be prepended to sys.path if present. +# defaults to the current working directory. +prepend_sys_path = . + +# timezone to use when rendering the date within the migration file +# as well as the filename. +# If specified, requires the python-dateutil library that can be +# installed by adding `alembic[tz]` to the pip requirements +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version number format +# version_num_format = %04d + +# version path separator; As mentioned above, this is the character used to split +# version_locations. The default within new alembic.ini files is "os", which uses +# os.pathsep. If this key is omitted entirely, it falls back to the legacy +# behavior of splitting on spaces and/or commas. +# Valid values for version_path_separator are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os + +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +sqlalchemy.url = postgresql://postgres:password@localhost:5432/nrcmvp + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks = black +# black.type = console_scripts +# black.entrypoint = black +# black.options = -l 79 REVISION_SCRIPT_FILENAME + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/backend/analyze_url_sources.py b/backend/analyze_url_sources.py new file mode 100644 index 000000000..a05b77bf6 --- /dev/null +++ b/backend/analyze_url_sources.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +""" +URL Sources Analysis - Why URLs are Missing in Most Cases + +This script analyzes the document processing pipeline to understand why URL sources +are not being properly preserved and linked to chunks in the knowledge graph. +""" + +import logging +import json +from typing import Dict, List, Any + +# Configure logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def analyze_url_source_issues(): + """ + Comprehensive analysis of why URL sources are missing in most cases. + """ + + print("๐Ÿ” URL SOURCES ANALYSIS: Why URLs Are Missing in Most Cases") + print("=" * 80) + + # Issue 1: Document Node Creation + print("\n๐Ÿ“‹ ISSUE 1: Document Node Creation") + print("-" * 50) + print("โœ… URLs ARE stored in Document nodes during creation:") + print(" - S3: obj_source_node.url = str(source_url+file_name)") + print(" - GCS: obj_source_node.url = file_metadata['url']") + print(" - Web: obj_source_node.url = urllib.parse.unquote(source_url)") + print(" - Wikipedia: obj_source_node.url = pages[0].metadata['source']") + print(" - YouTube: obj_source_node.url = source_url") + print(" - Local: โŒ NO URL stored (file_source = 'local file')") + + # Issue 2: Chunk Node Creation + print("\n๐Ÿ“‹ ISSUE 2: Chunk Node Creation") + print("-" * 50) + print("โŒ URLs are NOT copied to chunk nodes during creation:") + print(" - Chunk nodes only store: text, position, length, fileName, content_offset") + print(" - Missing: url, source_url, document_url properties") + print(" - Only relationship: (c:Chunk)-[:PART_OF]->(d:Document)") + + # Issue 3: Source Extraction Logic + print("\n๐Ÿ“‹ ISSUE 3: Source Extraction in Risk Assessment") + print("-" * 50) + print("๐Ÿ” Current extraction logic tries multiple fallbacks:") + print(" 1. node_props.get('url') - โŒ Chunks don't have URL property") + print(" 2. node_props.get('source_url') - โŒ Chunks don't have source_url property") + print(" 3. doc_info.get('url') - โœ… Document nodes have URL") + print(" 4. doc_info.get('source') - โŒ Document nodes don't have 'source' property") + print(" 5. node_props.get('source', '') - โŒ Chunks don't have source property") + + # Issue 4: Document-Chunk Relationship + print("\n๐Ÿ“‹ ISSUE 4: Document-Chunk Relationship") + print("-" * 50) + print("๐Ÿ”— Current relationship structure:") + print(" (c:Chunk)-[:PART_OF]->(d:Document)") + print(" - Chunk has: fileName property") + print(" - Document has: fileName and url properties") + print(" - โŒ No direct URL transfer during chunk creation") + + # Issue 5: Source Types Analysis + print("\n๐Ÿ“‹ ISSUE 5: Source Types Analysis") + print("-" * 50) + source_types = { + "local file": "โŒ No URL (local files)", + "s3 bucket": "โœ… Has URL (s3://bucket/path/file.pdf)", + "gcs bucket": "โœ… Has URL (https://storage.googleapis.com/...)", + "web page": "โœ… Has URL (https://example.com)", + "Wikipedia": "โœ… Has URL (https://en.wikipedia.org/wiki/...)", + "youtube": "โœ… Has URL (https://youtube.com/watch?v=...)" + } + + for source_type, url_status in source_types.items(): + print(f" {source_type:15} : {url_status}") + + # Issue 6: Risk Assessment Source Extraction + print("\n๐Ÿ“‹ ISSUE 6: Risk Assessment Source Extraction") + print("-" * 50) + print("๐Ÿ” Current extraction process:") + print(" 1. Extract subgraph with depth-based traversal") + print(" 2. Find Document nodes in subgraph") + print(" 3. Find Chunk nodes in subgraph") + print(" 4. Try to link chunks to document URLs") + print(" โŒ Problem: Not all Document nodes may be in subgraph") + print(" โŒ Problem: Chunk nodes don't have direct URL references") + + # Solutions + print("\n๐Ÿ’ก SOLUTIONS") + print("=" * 80) + + print("\n๐Ÿ”ง SOLUTION 1: Copy URL to Chunk Nodes") + print("-" * 40) + print("Modify create_relation_between_chunks() in make_relationships.py:") + print(""" + # Get document URL first + doc_url_query = "MATCH (d:Document {fileName: $f_name}) RETURN d.url as url" + doc_result = execute_graph_query(graph, doc_url_query, {"f_name": file_name}) + doc_url = doc_result[0]['url'] if doc_result else None + + # Add URL to chunk data + chunk_data = { + "id": current_chunk_id, + "pg_content": chunk_document.page_content, + "position": position, + "length": chunk_document.metadata["length"], + "f_name": file_name, + "url": doc_url, # โ† ADD THIS + "previous_id": previous_chunk_id, + "content_offset": offset + } + + # Update chunk creation query + query_to_create_chunk_and_PART_OF_relation = ''' + UNWIND $batch_data AS data + MERGE (c:Chunk {id: data.id}) + SET c.text = data.pg_content, c.position = data.position, + c.length = data.length, c.fileName=data.f_name, + c.url = data.url, c.content_offset=data.content_offset + ... + ''' + """) + + print("\n๐Ÿ”ง SOLUTION 2: Enhanced Source Extraction") + print("-" * 40) + print("Modify extract_chunks_from_subgraph() in risk_assessment.py:") + print(""" + # Add direct URL lookup for chunks + def get_document_url_for_chunk(chunk_file_name): + doc_url_query = "MATCH (d:Document {fileName: $f_name}) RETURN d.url as url" + doc_result = execute_graph_query(graph, doc_url_query, {"f_name": chunk_file_name}) + return doc_result[0]['url'] if doc_result else None + + # In chunk extraction loop + chunk_file_name = node_props.get('fileName') + if chunk_file_name: + doc_url = get_document_url_for_chunk(chunk_file_name) + if doc_url: + source_url = doc_url + """) + + print("\n๐Ÿ”ง SOLUTION 3: Improve Subgraph Extraction") + print("-" * 40) + print("Modify get_subgraph_from_node() to include Document nodes:") + print(""" + # Include Document nodes in subgraph extraction + subgraph_query = f''' + MATCH (startNode) + WHERE elementId(startNode) = $node_id + MATCH path = (startNode)-[*1..{depth}]-(connectedNode) + WITH startNode, collect(DISTINCT path) AS paths + UNWIND paths AS path + WITH startNode, path, nodes(path) AS pathNodes, relationships(path) AS pathRels + UNWIND pathNodes AS node + WITH startNode, path, pathRels, collect(DISTINCT node) AS allNodes + UNWIND pathRels AS rel + WITH startNode, allNodes, collect(DISTINCT rel) AS allRels + + // Also include Document nodes for chunks + WITH startNode, allNodes, allRels + OPTIONAL MATCH (c:Chunk)-[:PART_OF]->(d:Document) + WHERE c IN allNodes + WITH startNode, allNodes + collect(d) AS allNodes, allRels + RETURN allNodes AS nodes, allRels AS relationships + LIMIT $max_nodes + ''' + """) + + print("\n๐Ÿ”ง SOLUTION 4: Add URL Property to Chunk Schema") + print("-" * 40) + print("Update chunk creation to always include URL:") + print(""" + # In create_relation_between_chunks() + # Always get document URL, even for local files + doc_url = None + if file_name: + doc_url_query = "MATCH (d:Document {fileName: $f_name}) RETURN d.url as url, d.fileSource as source" + doc_result = execute_graph_query(graph, doc_url_query, {"f_name": file_name}) + if doc_result: + doc_url = doc_result[0]['url'] + file_source = doc_result[0]['source'] + if not doc_url and file_source == 'local file': + doc_url = f"local://{file_name}" # Create local file reference + + # Add to chunk data + chunk_data["url"] = doc_url + chunk_data["fileSource"] = file_source + """) + + print("\n๐Ÿ“Š SUMMARY") + print("=" * 80) + print("โœ… URLs ARE stored in Document nodes") + print("โŒ URLs are NOT copied to Chunk nodes") + print("โŒ Risk assessment can't easily access Document URLs") + print("โŒ Local files have no URL representation") + print("โŒ Subgraph extraction may not include Document nodes") + + print("\n๐ŸŽฏ RECOMMENDED FIXES (in order of impact):") + print("1. Copy URL from Document to Chunk nodes during creation") + print("2. Enhance subgraph extraction to include Document nodes") + print("3. Add direct URL lookup in risk assessment") + print("4. Create URL references for local files") + + print("\n๐Ÿš€ IMPLEMENTATION PRIORITY:") + print("HIGH: Solution 1 (Copy URL to Chunk nodes)") + print("MEDIUM: Solution 3 (Improve subgraph extraction)") + print("LOW: Solution 4 (Add URL property to schema)") + +if __name__ == "__main__": + analyze_url_source_issues() diff --git a/backend/debug_database.py b/backend/debug_database.py new file mode 100644 index 000000000..b963af13d --- /dev/null +++ b/backend/debug_database.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +""" +Debug script to check what's in the database +""" + +import sys +import os + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +def debug_database(): + """Check what documents exist in the database.""" + try: + from src.shared.common_fn import create_graph_database_connection + + # You'll need to update these connection details + uri = "neo4j+s://9379df68.databases.neo4j.io:7687" + username = "neo4j" + password = "your_password_here" # Update this with your actual password + database = "neo4j" + + print("๐Ÿ” Connecting to database...") + graph = create_graph_database_connection(uri, username, password, database) + + # Check what documents exist + print("\n๐Ÿ“„ Checking for documents...") + doc_query = """ + MATCH (d:Document) + RETURN d.fileName AS filename, d.id AS id, d.size AS size, d.created_date AS created_date + LIMIT 20 + """ + docs = graph.query(doc_query, {}) + print(f"Found {len(docs)} documents:") + for doc in docs: + print(f" - {doc['filename']} (ID: {doc['id']}, Size: {doc['size']})") + + # Check for specific document + target_doc = "Abiy_Ahmed" + print(f"\n๐ŸŽฏ Looking for document: {target_doc}") + + specific_query = """ + MATCH (d:Document {fileName: $doc_name}) + OPTIONAL MATCH (c:DocumentChunk)-[:BELONGS_TO]->(d) + RETURN d.fileName AS doc_name, count(c) AS chunk_count, d.id AS doc_id + """ + result = graph.query(specific_query, {"doc_name": target_doc}) + + if result: + doc_info = result[0] + print(f"โœ… Document found: {doc_info['doc_name']}") + print(f" Chunks: {doc_info['chunk_count']}") + print(f" ID: {doc_info['doc_id']}") + + if doc_info['chunk_count'] == 0: + print("โš ๏ธ Document exists but has no chunks!") + print(" This usually means the document was uploaded but never processed.") + + # Check if there are any chunks at all + chunk_query = """ + MATCH (c:DocumentChunk) + RETURN count(c) AS total_chunks + """ + chunk_result = graph.query(chunk_query, {}) + print(f" Total chunks in database: {chunk_result[0]['total_chunks']}") + else: + print(f"โŒ Document '{target_doc}' not found") + + # Check for similar names + similar_query = """ + MATCH (d:Document) + WHERE d.fileName CONTAINS 'Abiy' OR d.fileName CONTAINS 'Ahmed' + RETURN d.fileName AS filename + LIMIT 10 + """ + similar = graph.query(similar_query, {}) + if similar: + print("๐Ÿ” Similar document names found:") + for sim in similar: + print(f" - {sim['filename']}") + + # Check document status + print(f"\n๐Ÿ“Š Document Status Check:") + status_query = """ + MATCH (d:Document {fileName: $doc_name}) + RETURN d.Status AS status, d.processingTime AS processing_time, d.total_chunks AS total_chunks + """ + status_result = graph.query(status_query, {"doc_name": target_doc}) + if status_result: + status_info = status_result[0] + print(f" Status: {status_info['status']}") + print(f" Processing Time: {status_info['processing_time']}") + print(f" Total Chunks Expected: {status_info['total_chunks']}") + + except Exception as e: + print(f"โŒ Error: {e}") + print("\n๐Ÿ’ก Make sure to update the password in the script!") + print("๐Ÿ’ก Also check if you have the required dependencies installed") + +if __name__ == "__main__": + debug_database() diff --git a/backend/debug_monitoring_db.py b/backend/debug_monitoring_db.py new file mode 100644 index 000000000..124464df0 --- /dev/null +++ b/backend/debug_monitoring_db.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +""" +Debug script to check monitoring database state +""" + +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.monitoring_service_pg import MonitoringServicePG +from src.database import DatabaseManager + +def debug_monitoring_db(): + """Debug the monitoring database state""" + + print("๐Ÿ” Debugging Monitoring Database State") + print("=" * 50) + + try: + # Initialize monitoring service + monitoring_service = MonitoringServicePG() + + # Check schema + print("\n1๏ธโƒฃ Checking Monitoring Schema...") + schema_ok = monitoring_service.initialize_monitoring_schema() + print(f"Schema initialized: {schema_ok}") + + # Get monitored entities + print("\n2๏ธโƒฃ Monitored Entities in PostgreSQL...") + entities = monitoring_service.get_monitored_entities_from_db() + print(f"Found {len(entities)} monitored entities:") + for entity in entities: + print(f" - ID: {entity['id']}, Name: {entity['name']}, Type: {entity['type']}, Status: {entity['status']}") + print(f" Risk Threshold: {entity['risk_threshold']}, Category: {entity['category']}") + + # Check if Lori Greiner exists + print("\n3๏ธโƒฃ Checking for Lori Greiner...") + lori_entity = None + for entity in entities: + if "Lori" in entity['name'] or "Greiner" in entity['name']: + lori_entity = entity + break + + if lori_entity: + print(f"โœ… Found Lori Greiner: {lori_entity}") + else: + print("โŒ Lori Greiner not found in monitored entities") + + # Check alerts + print("\n4๏ธโƒฃ Current Alerts...") + alerts = monitoring_service.get_monitoring_alerts() + print(f"Found {len(alerts)} alerts:") + for alert in alerts: + print(f" - {alert['entity_name']}: {alert['message']} ({alert['severity']})") + + # Check risk assessments + print("\n5๏ธโƒฃ Risk Assessments...") + if lori_entity: + risk_assessment = monitoring_service.get_latest_risk_assessment(lori_entity['id']) + if risk_assessment: + print(f"Latest risk assessment for Lori: {risk_assessment}") + else: + print("No risk assessment found for Lori") + + # Check database directly + print("\n6๏ธโƒฃ Direct Database Query...") + db = DatabaseManager() + + # Check monitored_entities table + entities_result = db.execute_query("SELECT * FROM monitored_entities ORDER BY name") + print(f"Monitored entities table has {len(entities_result)} rows:") + for row in entities_result: + print(f" - {row}") + + # Check if there are any entities in Neo4j + print("\n7๏ธโƒฃ Checking Neo4j Connection...") + try: + from src.shared.common_fn import create_graph_database_connection + + # You'll need to provide actual connection details + print("Note: To check Neo4j, you need to provide connection details") + print("This would check if Lori Greiner exists as an entity in the graph") + + except Exception as e: + print(f"Error checking Neo4j: {e}") + + print("\n" + "=" * 50) + print("๐ŸŽฏ Debug Summary:") + print(f" โ€ข Monitored entities: {len(entities)}") + print(f" โ€ข Alerts: {len(alerts)}") + print(f" โ€ข Lori Greiner found: {'โœ…' if lori_entity else 'โŒ'}") + + if lori_entity: + print(f" โ€ข Lori entity ID: {lori_entity['id']}") + print(f" โ€ข Lori status: {lori_entity['status']}") + + except Exception as e: + print(f"\nโŒ Debug failed with error: {str(e)}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + debug_monitoring_db() diff --git a/backend/debug_url_extraction.py b/backend/debug_url_extraction.py new file mode 100644 index 000000000..7416df8f1 --- /dev/null +++ b/backend/debug_url_extraction.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +""" +Debug URL Extraction in Risk Assessment + +This script investigates why URLs aren't being extracted and displayed +in the risk assessment sources. +""" + +import os +import sys +import logging +from dotenv import load_dotenv + +# Add src to path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graph_query import search_and_get_subgraph +from src.shared.common_fn import create_graph_database_connection + +# Configure logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def debug_url_extraction(): + """ + Debug URL extraction for Bill Gates risk assessment. + """ + + # Load environment variables + load_dotenv() + + # Get database connection details + uri = os.getenv('NEO4J_URI', 'bolt://localhost:7687') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', 'password') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + try: + print("๐Ÿ” DEBUGGING URL EXTRACTION") + print("=" * 60) + + # Step 1: Get subgraph data + print("๐Ÿ“‹ Step 1: Getting subgraph data for Bill Gates...") + subgraph_data = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term="Bill Gates", + node_type="Person", + depth=4, + max_results=10, + extract_best_match_only=True, + preserve_text=True + ) + + if 'error' in subgraph_data: + print(f"โŒ Error getting subgraph: {subgraph_data['error']}") + return + + print(f"โœ… Got subgraph with {len(subgraph_data.get('subgraphs', []))} subgraphs") + + # Step 2: Examine Document nodes + print("\n๐Ÿ“‹ Step 2: Examining Document nodes...") + documents = {} + + for subgraph in subgraph_data.get('subgraphs', []): + for node in subgraph.get('nodes', []): + if 'Document' in node.get('labels', []): + doc_id = node.get('id') + doc_props = node.get('properties', {}) + + documents[doc_id] = { + 'file_name': doc_props.get('fileName'), + 'url': doc_props.get('url'), + 'file_source': doc_props.get('fileSource'), + 'source': doc_props.get('source'), + 'source_url': doc_props.get('source_url') + } + + print(f"๐Ÿ“„ Document: {doc_props.get('fileName', 'Unknown')}") + print(f" ID: {doc_id}") + print(f" URL: {doc_props.get('url', 'None')}") + print(f" File Source: {doc_props.get('fileSource', 'None')}") + print(f" Source: {doc_props.get('source', 'None')}") + print(f" Source URL: {doc_props.get('source_url', 'None')}") + print() + + print(f"๐Ÿ“Š Found {len(documents)} Document nodes") + + # Step 3: Examine Chunk nodes + print("\n๐Ÿ“‹ Step 3: Examining Chunk nodes...") + chunks = [] + + for subgraph in subgraph_data.get('subgraphs', []): + for node in subgraph.get('nodes', []): + if 'Chunk' in node.get('labels', []): + chunk_props = node.get('properties', {}) + + chunk_info = { + 'id': chunk_props.get('id'), + 'fileName': chunk_props.get('fileName'), + 'url': chunk_props.get('url'), + 'fileSource': chunk_props.get('fileSource'), + 'text_length': len(chunk_props.get('text', '')), + 'position': chunk_props.get('position') + } + + chunks.append(chunk_info) + + print(f"๐Ÿ“ Chunk: {chunk_props.get('id', 'Unknown')[:8]}...") + print(f" File: {chunk_props.get('fileName', 'None')}") + print(f" URL: {chunk_props.get('url', 'None')}") + print(f" File Source: {chunk_props.get('fileSource', 'None')}") + print(f" Text Length: {len(chunk_props.get('text', ''))}") + print() + + print(f"๐Ÿ“Š Found {len(chunks)} Chunk nodes") + + # Step 4: Check for URLs in chunks + print("\n๐Ÿ“‹ Step 4: URL Analysis...") + chunks_with_urls = [c for c in chunks if c['url']] + chunks_without_urls = [c for c in chunks if not c['url']] + + print(f"๐Ÿ“Š Chunks with URLs: {len(chunks_with_urls)}") + print(f"๐Ÿ“Š Chunks without URLs: {len(chunks_without_urls)}") + + if chunks_with_urls: + print("\nโœ… Chunks with URLs found:") + for chunk in chunks_with_urls: + print(f" Chunk {chunk['id'][:8]}... -> {chunk['url']}") + else: + print("\nโŒ No chunks have URL properties") + + # Check if documents have URLs + docs_with_urls = [d for d in documents.values() if d['url']] + print(f"\n๐Ÿ“Š Documents with URLs: {len(docs_with_urls)}") + + if docs_with_urls: + print("โœ… Documents with URLs found:") + for doc_name, doc_info in documents.items(): + if doc_info['url']: + print(f" {doc_info['file_name']} -> {doc_info['url']}") + else: + print("โŒ No documents have URL properties") + + # Step 5: Check database directly for URLs + print("\n๐Ÿ“‹ Step 5: Direct database query for URLs...") + + from src.shared.common_fn import execute_graph_query + + # Query for all Document nodes with URLs + doc_url_query = """ + MATCH (d:Document) + WHERE d.url IS NOT NULL + RETURN d.fileName as fileName, d.url as url, d.fileSource as fileSource + LIMIT 10 + """ + + doc_results = execute_graph_query(graph, doc_url_query) + print(f"๐Ÿ“Š Documents with URLs in database: {len(doc_results)}") + + for result in doc_results: + print(f" {result['fileName']} -> {result['url']} (Source: {result['fileSource']})") + + # Query for all Chunk nodes with URLs + chunk_url_query = """ + MATCH (c:Chunk) + WHERE c.url IS NOT NULL + RETURN c.fileName as fileName, c.url as url, c.fileSource as fileSource + LIMIT 10 + """ + + chunk_results = execute_graph_query(graph, chunk_url_query) + print(f"\n๐Ÿ“Š Chunks with URLs in database: {len(chunk_results)}") + + for result in chunk_results: + print(f" {result['fileName']} -> {result['url']} (Source: {result['fileSource']})") + + # Query for all nodes with any URL-related property + url_props_query = """ + MATCH (n) + WHERE n.url IS NOT NULL OR n.source_url IS NOT NULL OR n.source IS NOT NULL + RETURN labels(n) as labels, n.fileName as fileName, + n.url as url, n.source_url as source_url, n.source as source + LIMIT 20 + """ + + url_props_results = execute_graph_query(graph, url_props_query) + print(f"\n๐Ÿ“Š All nodes with URL-related properties: {len(url_props_results)}") + + for result in url_props_results: + labels = result['labels'] + print(f" {labels} - {result['fileName']}") + print(f" URL: {result['url']}") + print(f" Source URL: {result['source_url']}") + print(f" Source: {result['source']}") + print() + + graph.close() + + # Summary + print("\n๐Ÿ“ˆ SUMMARY") + print("=" * 60) + + if chunks_with_urls: + print("โœ… Chunks have URL properties - they should be used in risk assessment") + elif docs_with_urls: + print("โš ๏ธ Documents have URLs but chunks don't - URL copying may not be working") + else: + print("โŒ No URLs found in database - documents may not have URL properties") + + except Exception as e: + logger.error(f"Error debugging URL extraction: {str(e)}") + print(f"โŒ Error: {str(e)}") + finally: + if 'graph' in locals(): + graph.close() + +if __name__ == "__main__": + debug_url_extraction() diff --git a/backend/docs/risk_monitoring.md b/backend/docs/risk_monitoring.md new file mode 100644 index 000000000..f06126746 --- /dev/null +++ b/backend/docs/risk_monitoring.md @@ -0,0 +1,288 @@ +# Risk Monitoring System Documentation + +## Overview + +The Risk Monitoring System is a comprehensive solution for monitoring documents for specific names and risk indicators. It uses LLM-powered analysis to detect potential risks and generate alerts when thresholds are exceeded. + +## Features + +- **Name Monitoring**: Track specific names across document content +- **Risk Indicator Analysis**: Analyze documents for various risk indicators +- **Intelligent Scoring**: AI-powered risk assessment with configurable thresholds +- **Alert Generation**: Automatic alert creation for high-risk situations +- **Fallback Mechanisms**: Robust error handling with fallback analysis +- **Performance Tracking**: Comprehensive logging and performance metrics + +## API Endpoint + +### `/risk_monitor` + +**Method**: POST +**Content-Type**: application/x-www-form-urlencoded + +#### Parameters + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| `uri` | string | No | None | Database connection URI | +| `userName` | string | No | None | Database username | +| `password` | string | No | None | Database password | +| `database` | string | No | None | Database name | +| `document_name` | string | **Yes** | None | Name of document to monitor | +| `monitored_names` | string | No | [] | JSON array of names to monitor | +| `risk_indicators` | string | No | [] | JSON array of risk indicators | +| `risk_threshold` | float | No | 0.7 | Risk score threshold (0.0-1.0) | +| `model` | string | No | "gpt-4" | LLM model to use for analysis | +| `mode` | string | No | None | Processing mode | +| `email` | string | No | None | User email for logging | + +#### Example Request + +```bash +curl -X POST "http://localhost:8000/risk_monitor" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "document_name=sample_document.pdf" \ + -d "monitored_names=[\"John Doe\", \"Jane Smith\"]" \ + -d "risk_indicators=[\"financial_fraud\", \"regulatory_violation\"]" \ + -d "risk_threshold=0.6" \ + -d "model=gpt-4" +``` + +## Risk Indicators + +### Predefined Risk Categories + +1. **Financial Risks** + - `financial_fraud` + - `money_laundering` + - `insider_trading` + - `accounting_fraud` + +2. **Regulatory Risks** + - `regulatory_violation` + - `compliance_breach` + - `licensing_issues` + - `regulatory_investigation` + +3. **Operational Risks** + - `data_breach` + - `cybersecurity_threat` + - `operational_disruption` + - `supply_chain_risk` + +4. **Reputational Risks** + - `negative_publicity` + - `customer_complaints` + - `employee_misconduct` + - `ethical_violations` + +## Response Format + +### Success Response + +```json +{ + "status": "Success", + "data": { + "success": true, + "document_name": "sample_document.pdf", + "monitoring_summary": { + "names_monitored": 2, + "risk_indicators_checked": 2, + "risk_threshold": 0.6, + "total_risk_score": 0.75, + "alert_required": true + }, + "name_monitoring": { + "names_found": [ + { + "name": "John Doe", + "occurrences": [ + { + "chunk": 1, + "context": "John Doe was mentioned in connection with...", + "risk_score": 0.8 + } + ], + "overall_risk_score": 0.8 + } + ] + }, + "risk_analysis": { + "indicators_found": [ + { + "indicator": "financial_fraud", + "evidence": "Mention of suspicious financial transactions...", + "severity": "high", + "risk_score": 0.9, + "impact": "Potential financial loss and regulatory violations" + } + ] + }, + "risk_assessment": { + "overall_risk_score": 0.75, + "name_risk_score": 0.8, + "indicator_risk_score": 0.9, + "alert_required": true, + "risk_level": "HIGH" + }, + "alerts": [ + { + "type": "HIGH_RISK", + "score": 0.75, + "description": "Overall risk score 0.75 exceeds threshold 0.6", + "timestamp": "2024-01-15T10:30:00" + } + ], + "info": { + "processing_time": 0, + "document_size": 1024000, + "chunks_analyzed": 15, + "model_used": "gpt-4", + "response_time": 2.34 + } + } +} +``` + +### Error Response + +```json +{ + "status": "Failed", + "message": "Unable to perform risk monitoring", + "error": "Document 'nonexistent.pdf' not found" +} +``` + +## Risk Levels + +| Level | Score Range | Color | Action Required | +|-------|-------------|-------|-----------------| +| LOW | 0.0 - 0.3 | Green | Monitor | +| MEDIUM | 0.3 - 0.7 | Yellow | Review | +| HIGH | 0.7 - 1.0 | Red | Immediate Action Required | + +## Implementation Details + +### Core Functions + +1. **`perform_risk_monitoring()`**: Main orchestration function +2. **`monitor_names_in_document()`**: Name monitoring with LLM analysis +3. **`analyze_risk_indicators()`**: Risk indicator analysis +4. **`generate_risk_assessment()`**: Risk scoring and alert generation + +### LLM Integration + +- Uses OpenAI GPT-4 by default +- Configurable model selection +- Structured prompt engineering +- JSON response parsing with fallbacks + +### Database Queries + +- Document existence validation +- Chunk extraction for analysis +- Efficient Neo4j graph queries +- Metadata preservation + +### Error Handling + +- Graceful degradation on LLM failures +- Fallback text-based analysis +- Comprehensive logging +- User-friendly error messages + +## Usage Examples + +### Basic Name Monitoring + +```python +from src.risk_monitor import perform_risk_monitoring + +result = perform_risk_monitoring( + graph=graph_connection, + document_name="financial_report.pdf", + monitored_names=["John Doe", "Acme Corp"], + risk_indicators=[], + risk_threshold=0.7 +) +``` + +### Comprehensive Risk Analysis + +```python +result = perform_risk_monitoring( + graph=graph_connection, + document_name="compliance_document.pdf", + monitored_names=["Jane Smith"], + risk_indicators=[ + "financial_fraud", + "regulatory_violation", + "data_breach" + ], + risk_threshold=0.5, + model="gpt-4" +) +``` + +## Performance Considerations + +- **Chunk Processing**: Documents are processed in chunks for efficiency +- **LLM Optimization**: Temperature set to 0.1 for consistent results +- **Caching**: Consider implementing response caching for repeated queries +- **Async Processing**: Endpoint supports asynchronous processing + +## Security Features + +- Input validation and sanitization +- Access control integration +- Secure logging (passwords masked) +- Rate limiting considerations + +## Monitoring and Logging + +- Structured logging with JSON format +- Performance metrics tracking +- Error tracking and alerting +- User activity monitoring + +## Troubleshooting + +### Common Issues + +1. **Document Not Found** + - Verify document exists in database + - Check document name spelling + - Ensure proper database connection + +2. **LLM Analysis Failures** + - Check API key configuration + - Verify model availability + - Review prompt formatting + +3. **Performance Issues** + - Monitor chunk sizes + - Check database performance + - Review LLM response times + +### Debug Mode + +Enable detailed logging by setting log level to DEBUG: + +```python +import logging +logging.basicConfig(level=logging.DEBUG) +``` + +## Future Enhancements + +- **Batch Processing**: Monitor multiple documents simultaneously +- **Real-time Monitoring**: Continuous monitoring with webhooks +- **Custom Risk Models**: User-defined risk assessment models +- **Integration APIs**: Connect with external risk management systems +- **Machine Learning**: Enhanced risk scoring with ML models + +## Support + +For technical support or questions about the Risk Monitoring System, please refer to the project documentation or contact the development team. diff --git a/backend/example.env b/backend/example.env index c0c24a90e..0f0d543fd 100644 --- a/backend/example.env +++ b/backend/example.env @@ -9,10 +9,24 @@ GEMINI_ENABLED = False GCP_LOG_METRICS_ENABLED = False NUMBER_OF_CHUNKS_TO_COMBINE = 6 UPDATE_GRAPH_CHUNKS_PROCESSED = 20 +# PostgreSQL Database Configuration +DATABASE_URL = "postgresql://postgres:password@localhost:5432/nrcmvp" +# Alternative: Use individual environment variables +POSTGRES_HOST = "localhost" +POSTGRES_PORT = "5432" +POSTGRES_DB = "nrcmvp" +POSTGRES_USER = "postgres" +POSTGRES_PASSWORD = "password" + +# Neo4j Configuration (for existing graph operations) NEO4J_URI = "" NEO4J_USERNAME = "" NEO4J_PASSWORD = "" NEO4J_DATABASE = "" + +# MCP Server Configuration +# Set MCP_SERVER_URL to use remote server, leave empty for local server +MCP_SERVER_URL = "https://mcp-server.com" AWS_ACCESS_KEY_ID = "" AWS_SECRET_ACCESS_KEY = "" LANGCHAIN_API_KEY = "" @@ -54,4 +68,11 @@ LLM_MODEL_CONFIG_bedrock_nova_lite_v1="model_name,aws_access_key,aws_secret_key, LLM_MODEL_CONFIG_bedrock_nova_pro_v1="model_name,aws_access_key,aws_secret_key,region_name" #model_name="amazon.nova-pro-v1:0" LLM_MODEL_CONFIG_fireworks_deepseek_r1="model_name,fireworks_api_key" #model_name="accounts/fireworks/models/deepseek-r1" LLM_MODEL_CONFIG_fireworks_deepseek_v3="model_name,fireworks_api_key" #model_name="accounts/fireworks/models/deepseek-v3" -MAX_TOKEN_CHUNK_SIZE=2000 #Max token used to process/extract the file content. \ No newline at end of file +MAX_TOKEN_CHUNK_SIZE=2000 #Max token used to process/extract the file content. + + +DATABASE_URL="postgresql://postgres:password@localhost:5432/nrcmvp" + + + +LLM_MODEL_CONFIG_openai_gpt_4.1="" \ No newline at end of file diff --git a/backend/explain_nil_sources.py b/backend/explain_nil_sources.py new file mode 100644 index 000000000..9a83e862f --- /dev/null +++ b/backend/explain_nil_sources.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +""" +Script to explain why sources show as "nil" in risk assessments. +""" + +def explain_nil_sources(): + """Explain why sources might show as "nil" in risk assessments.""" + + print("๐Ÿ” Understanding 'nil' Sources in Risk Assessment") + print("=" * 60) + + print("\n๐Ÿ“‹ Why do some risk indicators show 'nil' sources?") + print("\nThe 'nil' sources appear when the LLM determines that:") + print("1. No evidence exists in the provided chunks for that specific risk indicator") + print("2. The chunks don't contain relevant information for that particular risk factor") + print("3. The LLM cannot find supporting evidence in the available context") + + print("\n๐Ÿ“Š Example from your results:") + print(""" +Foreign State Influence: Sources: ["nil"] +- This means the chunks don't contain evidence of foreign state influence +- The LLM correctly identifies no supporting evidence +- This is actually GOOD - it means the system is not hallucinating + +Dual-Use Technology Exposure: Sources: ["Chunk 5", "Chunk 7"] +- This means chunks 5 and 7 contain relevant evidence +- The LLM found supporting information in these chunks +- This shows the system is working correctly + """) + + print("\n๐ŸŽฏ This is Expected Behavior:") + print("โœ… 'nil' sources indicate honest assessment - no evidence found") + print("โœ… Chunk references indicate evidence was found and used") + print("โœ… The LLM is following instructions to not hallucinate") + + print("\n๐Ÿ”ง To Get Better Sources:") + print("1. Ensure your database contains documents with relevant information") + print("2. Check that document sources/URLs are properly stored") + print("3. Verify that chunks are being extracted with source information") + print("4. Consider adding more diverse documents to your knowledge graph") + + print("\n๐Ÿ“ Current Source Types:") + print("- 'nil': No evidence found (correct behavior)") + print("- 'Chunk X': Evidence found in chunk X (working correctly)") + print("- 'Document: filename.pdf': Document name available") + print("- 'https://...': Actual URL available (ideal)") + + print("\nโœ… Your system is working correctly!") + print("The 'nil' sources are a sign of honest, evidence-based assessment.") + +if __name__ == "__main__": + explain_nil_sources() diff --git a/backend/fix_chunk_urls.py b/backend/fix_chunk_urls.py new file mode 100644 index 000000000..12268a824 --- /dev/null +++ b/backend/fix_chunk_urls.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +""" +Fix Chunk URLs - Copy URL Properties from Documents to Chunks + +This script updates all Chunk nodes to copy URL and fileSource properties +from their parent Document nodes, enabling proper URL citations in risk assessment. +""" + +import os +import sys +import logging +from dotenv import load_dotenv + +# Add src to path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.shared.common_fn import create_graph_database_connection, execute_graph_query + +# Configure logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def fix_chunk_urls(): + """ + Copy URL properties from Document nodes to their associated Chunk nodes. + """ + + # Load environment variables + load_dotenv() + + # Get database connection details + uri = os.getenv('NEO4J_URI', 'bolt://localhost:7687') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', 'password') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + try: + print("๐Ÿ”ง FIXING CHUNK URLS - COPYING FROM DOCUMENTS") + print("=" * 60) + + # Connect to database + graph = create_graph_database_connection(uri, username, password, database) + + # Step 1: Check current state + print("\n๐Ÿ“‹ Step 1: Checking current state") + + # Count documents with URLs + doc_url_query = """ + MATCH (d:Document) + WHERE d.url IS NOT NULL + RETURN count(d) as docs_with_urls + """ + doc_result = execute_graph_query(graph, doc_url_query) + docs_with_urls = doc_result[0]['docs_with_urls'] if doc_result else 0 + + # Count chunks with URLs + chunk_url_query = """ + MATCH (c:Chunk) + WHERE c.url IS NOT NULL + RETURN count(c) as chunks_with_urls + """ + chunk_result = execute_graph_query(graph, chunk_url_query) + chunks_with_urls = chunk_result[0]['chunks_with_urls'] if chunk_result else 0 + + # Count total chunks + total_chunks_query = """ + MATCH (c:Chunk) + RETURN count(c) as total_chunks + """ + total_result = execute_graph_query(graph, total_chunks_query) + total_chunks = total_result[0]['total_chunks'] if total_result else 0 + + print(f"๐Ÿ“Š Documents with URLs: {docs_with_urls}") + print(f"๐Ÿ“Š Chunks with URLs: {chunks_with_urls}") + print(f"๐Ÿ“Š Total chunks: {total_chunks}") + + # Step 2: Show documents with URLs + print("\n๐Ÿ“‹ Step 2: Documents with URLs") + doc_details_query = """ + MATCH (d:Document) + WHERE d.url IS NOT NULL + RETURN d.fileName as fileName, d.url as url, d.fileSource as fileSource + LIMIT 10 + """ + doc_details = execute_graph_query(graph, doc_details_query) + + for doc in doc_details: + print(f" ๐Ÿ“„ {doc['fileName']}") + print(f" URL: {doc['url']}") + print(f" Source: {doc['fileSource']}") + + # Step 3: Find chunks that need URL properties + print("\n๐Ÿ“‹ Step 3: Finding chunks that need URL properties") + chunks_needing_urls_query = """ + MATCH (c:Chunk)-[:PART_OF]->(d:Document) + WHERE c.url IS NULL AND d.url IS NOT NULL + RETURN count(c) as chunks_needing_urls + """ + chunks_needing_result = execute_graph_query(graph, chunks_needing_urls_query) + chunks_needing_urls = chunks_needing_result[0]['chunks_needing_urls'] if chunks_needing_result else 0 + + print(f"๐Ÿ“Š Chunks needing URL properties: {chunks_needing_urls}") + + if chunks_needing_urls == 0: + print("โœ… All chunks already have URL properties!") + return + + # Step 4: Update chunks with URL properties + print("\n๐Ÿ“‹ Step 4: Updating chunks with URL properties") + update_query = """ + MATCH (c:Chunk)-[:PART_OF]->(d:Document) + WHERE c.url IS NULL AND d.url IS NOT NULL + SET c.url = d.url, c.fileSource = d.fileSource + RETURN count(c) as updated_count + """ + + update_result = execute_graph_query(graph, update_query) + updated_count = update_result[0]['updated_count'] if update_result else 0 + print(f"๐Ÿ“Š Successfully updated {updated_count} chunks with URL properties") + + # Step 5: Verify the fix + print("\n๐Ÿ“‹ Step 5: Verifying the fix") + + # Check updated chunks + verify_query = """ + MATCH (c:Chunk) + WHERE c.url IS NOT NULL + RETURN c.fileName as fileName, c.url as url, c.fileSource as fileSource + LIMIT 5 + """ + verify_results = execute_graph_query(graph, verify_query) + + print(f"๐Ÿ“Š Chunks with URLs after fix: {len(verify_results)}") + for result in verify_results: + print(f" ๐Ÿ“ {result['fileName']} -> {result['url']} (Source: {result['fileSource']})") + + # Step 6: Check Bill Gates chunks specifically + print("\n๐Ÿ“‹ Step 6: Bill Gates chunks after fix") + bill_gates_query = """ + MATCH (c:Chunk) + WHERE c.fileName = 'Bill_Gates' AND c.url IS NOT NULL + RETURN c.fileName as fileName, c.url as url, c.fileSource as fileSource + LIMIT 3 + """ + bill_gates_results = execute_graph_query(graph, bill_gates_query) + + print(f"๐Ÿ“Š Bill Gates chunks with URLs: {len(bill_gates_results)}") + for result in bill_gates_results: + print(f" ๐Ÿ“ {result['fileName']} -> {result['url']} (Source: {result['fileSource']})") + + # Step 7: Final statistics + print("\n๐Ÿ“‹ Step 7: Final statistics") + final_stats_query = """ + MATCH (c:Chunk) + RETURN + count(c) as total_chunks, + count(CASE WHEN c.url IS NOT NULL THEN c END) as chunks_with_urls, + count(CASE WHEN c.url IS NULL THEN c END) as chunks_without_urls + """ + final_stats = execute_graph_query(graph, final_stats_query) + + if final_stats: + stats = final_stats[0] + print(f"๐Ÿ“Š Total chunks: {stats['total_chunks']}") + print(f"๐Ÿ“Š Chunks with URLs: {stats['chunks_with_urls']}") + print(f"๐Ÿ“Š Chunks without URLs: {stats['chunks_without_urls']}") + + if stats['total_chunks'] > 0: + coverage = (stats['chunks_with_urls'] / stats['total_chunks']) * 100 + print(f"๐Ÿ“Š URL coverage: {coverage:.1f}%") + + graph.close() + + # Summary + print("\n๐Ÿ“ˆ SUMMARY") + print("=" * 60) + + if updated_count > 0: + print(f"โœ… Successfully updated {updated_count} chunks with URL properties") + print("โœ… Risk assessment should now show actual URLs instead of 'Chunk X'") + print("โœ… Example: 'https://en.wikipedia.org/wiki/Bill_Gates' instead of 'Chunk 7'") + else: + print("โ„น๏ธ No chunks needed updating - they already have URL properties") + + print("\n๐Ÿš€ Next Steps:") + print(" 1. Run a risk assessment to see the improved URL citations") + print(" 2. Check that sources now show actual URLs") + print(" 3. Verify that 'Chunk X' references are replaced with document URLs") + + except Exception as e: + logger.error(f"Error fixing chunk URLs: {str(e)}") + print(f"โŒ Error: {str(e)}") + +if __name__ == "__main__": + fix_chunk_urls() diff --git a/backend/migrations/env.py b/backend/migrations/env.py new file mode 100644 index 000000000..aca97f385 --- /dev/null +++ b/backend/migrations/env.py @@ -0,0 +1,109 @@ +""" +Alembic environment configuration for PostgreSQL migrations +""" + +import os +import sys +from logging.config import fileConfig +from sqlalchemy import engine_from_config, pool +from alembic import context + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +# Import your models here +from src.database import DatabaseManager + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def get_database_url(): + """Get database URL from environment variables""" + database_url = os.getenv("DATABASE_URL") + + if database_url: + return database_url + + # Fallback to individual environment variables + host = os.getenv("POSTGRES_HOST", "localhost") + port = os.getenv("POSTGRES_PORT", "5432") + database = os.getenv("POSTGRES_DB", "monitoring_db") + user = os.getenv("POSTGRES_USER", "postgres") + password = os.getenv("POSTGRES_PASSWORD", "password") + + return f"postgresql://{user}:{password}@{host}:{port}/{database}" + + +def run_migrations_offline() -> None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = get_database_url() + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + url = get_database_url() + + # Override the sqlalchemy.url in the config + config.set_main_option("sqlalchemy.url", url) + + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/backend/migrations/versions/001_initial_monitoring_schema.py b/backend/migrations/versions/001_initial_monitoring_schema.py new file mode 100644 index 000000000..ee24431c3 --- /dev/null +++ b/backend/migrations/versions/001_initial_monitoring_schema.py @@ -0,0 +1,86 @@ +""" +Initial monitoring schema migration + +Revision ID: 001 +Revises: +Create Date: 2024-01-01 00:00:00.000000 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '001' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade() -> None: + """Create initial monitoring schema""" + + # Create monitored_entities table + op.create_table('monitored_entities', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(length=255), nullable=False), + sa.Column('type', sa.String(length=50), nullable=False), + sa.Column('risk_threshold', sa.Numeric(precision=3, scale=2), nullable=True), + sa.Column('category', sa.String(length=100), nullable=True), + sa.Column('status', sa.String(length=20), nullable=True), + sa.Column('created_at', sa.TIMESTAMP(), nullable=True), + sa.Column('updated_at', sa.TIMESTAMP(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + + # Create risk_assessments table + op.create_table('risk_assessments', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('entity_id', sa.Integer(), nullable=True), + sa.Column('risk_score', sa.Numeric(precision=3, scale=2), nullable=False), + sa.Column('risk_level', sa.String(length=20), nullable=False), + sa.Column('connections_count', sa.Integer(), nullable=True), + sa.Column('risk_indicators', postgresql.ARRAY(sa.String()), nullable=True), + sa.Column('timestamp', sa.TIMESTAMP(), nullable=True), + sa.ForeignKeyConstraint(['entity_id'], ['monitored_entities.id'], ), + sa.PrimaryKeyConstraint('id') + ) + + # Create alerts table + op.create_table('alerts', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('entity_id', sa.Integer(), nullable=True), + sa.Column('severity', sa.String(length=20), nullable=False), + sa.Column('message', sa.Text(), nullable=False), + sa.Column('timestamp', sa.TIMESTAMP(), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=True), + sa.ForeignKeyConstraint(['entity_id'], ['monitored_entities.id'], ), + sa.PrimaryKeyConstraint('id') + ) + + # Create indexes for better performance + op.create_index('idx_monitored_entities_name', 'monitored_entities', ['name']) + op.create_index('idx_monitored_entities_status', 'monitored_entities', ['status']) + op.create_index('idx_risk_assessments_entity_id', 'risk_assessments', ['entity_id']) + op.create_index('idx_risk_assessments_timestamp', 'risk_assessments', ['timestamp']) + op.create_index('idx_alerts_entity_id', 'alerts', ['entity_id']) + op.create_index('idx_alerts_timestamp', 'alerts', ['timestamp']) + op.create_index('idx_alerts_is_active', 'alerts', ['is_active']) + + +def downgrade() -> None: + """Drop initial monitoring schema""" + + # Drop indexes + op.drop_index('idx_alerts_is_active', table_name='alerts') + op.drop_index('idx_alerts_timestamp', table_name='alerts') + op.drop_index('idx_alerts_entity_id', table_name='alerts') + op.drop_index('idx_risk_assessments_timestamp', table_name='risk_assessments') + op.drop_index('idx_risk_assessments_entity_id', table_name='risk_assessments') + op.drop_index('idx_monitored_entities_status', table_name='monitored_entities') + op.drop_index('idx_monitored_entities_name', table_name='monitored_entities') + + # Drop tables + op.drop_table('alerts') + op.drop_table('risk_assessments') + op.drop_table('monitored_entities') diff --git a/backend/migrations/versions/002_add_subgraph_tracking.py b/backend/migrations/versions/002_add_subgraph_tracking.py new file mode 100644 index 000000000..057965d8b --- /dev/null +++ b/backend/migrations/versions/002_add_subgraph_tracking.py @@ -0,0 +1,62 @@ +""" +Add subgraph tracking to monitored entities + +Revision ID: 002 +Revises: 001 +Create Date: 2025-09-02 23:15:00.000000 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '002' +down_revision = '001' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + """Add subgraph tracking fields and table""" + + # Add subgraph tracking fields to monitored_entities table + op.add_column('monitored_entities', sa.Column('last_subgraph_nodes', sa.Integer(), nullable=True)) + op.add_column('monitored_entities', sa.Column('last_subgraph_relationships', sa.Integer(), nullable=True)) + op.add_column('monitored_entities', sa.Column('last_subgraph_timestamp', sa.TIMESTAMP(), nullable=True)) + op.add_column('monitored_entities', sa.Column('subgraph_signature', sa.String(length=255), nullable=True)) + + # Create subgraph_snapshots table for historical tracking + op.create_table('subgraph_snapshots', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('entity_id', sa.Integer(), nullable=True), + sa.Column('node_count', sa.Integer(), nullable=False), + sa.Column('relationship_count', sa.Integer(), nullable=False), + sa.Column('subgraph_signature', sa.String(length=255), nullable=True), + sa.Column('timestamp', sa.TIMESTAMP(), nullable=True), + sa.ForeignKeyConstraint(['entity_id'], ['monitored_entities.id'], ), + sa.PrimaryKeyConstraint('id') + ) + + # Create indexes for better performance + op.create_index('idx_subgraph_snapshots_entity_id', 'subgraph_snapshots', ['entity_id']) + op.create_index('idx_subgraph_snapshots_timestamp', 'subgraph_snapshots', ['timestamp']) + op.create_index('idx_monitored_entities_subgraph_signature', 'monitored_entities', ['subgraph_signature']) + + +def downgrade() -> None: + """Remove subgraph tracking fields and table""" + + # Drop indexes + op.drop_index('idx_monitored_entities_subgraph_signature', table_name='monitored_entities') + op.drop_index('idx_subgraph_snapshots_timestamp', table_name='subgraph_snapshots') + op.drop_index('idx_subgraph_snapshots_entity_id', table_name='subgraph_snapshots') + + # Drop subgraph_snapshots table + op.drop_table('subgraph_snapshots') + + # Remove columns from monitored_entities table + op.drop_column('monitored_entities', 'subgraph_signature') + op.drop_column('monitored_entities', 'last_subgraph_timestamp') + op.drop_column('monitored_entities', 'last_subgraph_relationships') + op.drop_column('monitored_entities', 'last_subgraph_nodes') diff --git a/backend/migrations/versions/003_update_alerts_schema.py b/backend/migrations/versions/003_update_alerts_schema.py new file mode 100644 index 000000000..8f3fdec74 --- /dev/null +++ b/backend/migrations/versions/003_update_alerts_schema.py @@ -0,0 +1,72 @@ +""" +Update alerts schema to match LLM alert structure + +Revision ID: 003 +Revises: 002 +Create Date: 2025-09-04 21:00:00.000000 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '003' +down_revision = '002' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + """Update alerts table to match LLM alert structure""" + + # Add new columns to match LLM alert structure (only if they don't exist) + try: + op.add_column('alerts', sa.Column('type', sa.String(length=50), nullable=True)) + except: + pass # Column already exists + + try: + op.add_column('alerts', sa.Column('score', sa.Numeric(precision=3, scale=2), nullable=True)) + except: + pass # Column already exists + + try: + op.add_column('alerts', sa.Column('evidence', sa.Text(), nullable=True)) + except: + pass # Column already exists + + try: + op.add_column('alerts', sa.Column('indicator', sa.String(length=255), nullable=True)) + except: + pass # Column already exists + + try: + op.add_column('alerts', sa.Column('name', sa.String(length=255), nullable=True)) + except: + pass # Column already exists + + try: + op.add_column('alerts', sa.Column('context', sa.Text(), nullable=True)) + except: + pass # Column already exists + + # Note: New columns will have NULL values for existing records + # This is fine as the application will handle the new structure + + +def downgrade() -> None: + """Revert alerts table changes""" + + # Revert column names + op.alter_column('alerts', 'description', new_column_name='message') + op.alter_column('alerts', 'type', new_column_name='severity') + + # Remove new columns + op.drop_column('alerts', 'context') + op.drop_column('alerts', 'name') + op.drop_column('alerts', 'indicator') + op.drop_column('alerts', 'evidence') + op.drop_column('alerts', 'description') + op.drop_column('alerts', 'score') + op.drop_column('alerts', 'type') diff --git a/backend/requirements.txt b/backend/requirements.txt index 914bbf19d..794359556 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,5 +1,6 @@ accelerate==1.7.0 -asyncio==3.4.3 +mcp-neo4j-cypher>=0.3.1 +httpx>=0.25.0 boto3==1.38.36 botocore==1.38.36 certifi==2025.6.15 @@ -29,11 +30,11 @@ langsmith==0.3.45 langserve==0.3.1 neo4j-rust-ext==5.28.1.0 nltk==3.9.1 -openai==1.86.0 +openai>=1.68.2,<2.0.0 opencv-python==4.11.0.86 psutil==7.0.0 pydantic==2.11.7 -python-dotenv==1.1.0 +python-dotenv>=1.1.0 python-magic==0.4.27 PyPDF2==3.0.1 PyMuPDF==1.26.1 @@ -62,4 +63,6 @@ ragas==0.2.15 rouge_score==0.1.2 langchain-neo4j==0.4.0 pypandoc-binary==1.15 -chardet==5.2.0 \ No newline at end of file +chardet==5.2.0 +psycopg2-binary==2.9.9 +alembic==1.13.1 \ No newline at end of file diff --git a/backend/risk_assessment_Bill_Gates.json b/backend/risk_assessment_Bill_Gates.json new file mode 100644 index 000000000..fc71ebbdf --- /dev/null +++ b/backend/risk_assessment_Bill_Gates.json @@ -0,0 +1,82 @@ +{ + "entityName": "Bill Gates", + "entityType": "individual", + "riskAssessments": [ + { + "indicator": "Foreign State Influence", + "weight": 80, + "score": 2, + "explanation": "No evidence was found in the provided context to suggest significant foreign state influence on Bill Gates. His work is primarily focused on philanthropy and technology, with no direct ties to foreign state actors mentioned.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.32, + "weightedContribution": 0.64 + }, + { + "indicator": "Dual-Use Technology Exposure", + "weight": 70, + "score": 3, + "explanation": "As a co-founder of Microsoft, Bill Gates has been involved in the development of technologies that could have dual-use potential. However, his current focus on philanthropy reduces the likelihood of active exposure to dual-use technology risks.", + "sources": [ + "Chunk 1", + "Chunk 2" + ], + "normalizedWeight": 0.28, + "weightedContribution": 0.84 + }, + { + "indicator": "Compliance with Canadian Research Security Policies", + "weight": 60, + "score": 2, + "explanation": "No evidence was found in the provided context to suggest non-compliance with Canadian research security policies. Gates' philanthropic work and technology contributions do not appear to directly intersect with Canadian research security frameworks.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.24, + "weightedContribution": 0.48 + }, + { + "indicator": "International Collaboration Patterns", + "weight": 50, + "score": 3, + "explanation": "Bill Gates is known for extensive international collaboration through the Bill & Melinda Gates Foundation, particularly in health and education. While these collaborations are generally transparent, they could pose moderate risks depending on the partners involved.", + "sources": [ + "Chunk 3" + ], + "normalizedWeight": 0.2, + "weightedContribution": 0.6 + }, + { + "indicator": "Funding Sources Transparency", + "weight": 40, + "score": 2, + "explanation": "The Bill & Melinda Gates Foundation is known for its transparency in funding sources. No evidence was found to suggest a lack of transparency in Gates' funding activities.", + "sources": [ + "Chunk 3" + ], + "normalizedWeight": 0.16, + "weightedContribution": 0.32 + } + ], + "calculation": { + "totalWeight": 300, + "overallScore": 2.88, + "thresholdsApplied": { + "red": "overallScore >= 4.0", + "yellow": "2.5 <= overallScore < 4.0", + "blue": "overallScore < 2.5" + } + }, + "finalAssessment": { + "trafficLight": "Yellow", + "overallExplanation": "Bill Gates presents a moderate research-security risk primarily due to his historical involvement in dual-use technology and extensive international collaborations. However, his current focus on philanthropy and transparency in funding reduces the overall risk." + }, + "analysis_metadata": { + "chunks_analyzed": 10, + "subgraph_nodes": 139, + "subgraph_relationships": 276, + "search_method": "unknown", + "best_match_score": 0.9 + } +} \ No newline at end of file diff --git a/backend/risk_assessment_Microsoft.json b/backend/risk_assessment_Microsoft.json new file mode 100644 index 000000000..e073576b4 --- /dev/null +++ b/backend/risk_assessment_Microsoft.json @@ -0,0 +1,81 @@ +{ + "entityName": "Microsoft", + "entityType": "organization", + "riskAssessments": [ + { + "indicator": "Foreign State Influence", + "weight": 80, + "score": 3, + "explanation": "No specific evidence of foreign state influence on Microsoft was found in the provided data. However, as a major multinational technology company, Microsoft operates in numerous jurisdictions, which could expose it to potential foreign state influence risks.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.32, + "weightedContribution": 0.96 + }, + { + "indicator": "Dual-Use Technology Exposure", + "weight": 70, + "score": 4, + "explanation": "Microsoft develops advanced technologies, including AI and cloud computing, which have potential dual-use applications. This increases the risk of misuse in sensitive contexts.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.28, + "weightedContribution": 1.12 + }, + { + "indicator": "Compliance with Canadian Research Security Policies", + "weight": 60, + "score": 2, + "explanation": "No evidence was found in the provided data regarding Microsoft's compliance with Canadian research security policies. As a global corporation, Microsoft likely has compliance frameworks, but specific alignment with Canadian policies is unclear.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.24, + "weightedContribution": 0.48 + }, + { + "indicator": "International Collaboration Patterns", + "weight": 50, + "score": 3, + "explanation": "Microsoft engages in extensive international collaborations, which could pose moderate risks depending on the nature of partnerships and jurisdictions involved. No specific evidence was found in the provided data.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.2, + "weightedContribution": 0.6 + }, + { + "indicator": "Funding Sources Transparency", + "weight": 40, + "score": 2, + "explanation": "No evidence was found in the provided data regarding transparency of Microsoft's funding sources. As a publicly traded company, Microsoft is subject to financial disclosure requirements, which likely mitigates this risk.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.16, + "weightedContribution": 0.32 + } + ], + "calculation": { + "totalWeight": 300, + "overallScore": 3.48, + "thresholdsApplied": { + "red": "overallScore >= 4.0", + "yellow": "2.5 <= overallScore < 4.0", + "blue": "overallScore < 2.5" + } + }, + "finalAssessment": { + "trafficLight": "Yellow", + "overallExplanation": "Microsoft presents moderate research-security risks due to its exposure to dual-use technologies and international collaborations. Limited evidence on compliance with Canadian policies and funding transparency further contributes to the assessment." + }, + "analysis_metadata": { + "chunks_analyzed": 10, + "subgraph_nodes": 104, + "subgraph_relationships": 226, + "search_method": "unknown", + "best_match_score": 0.2669 + } +} \ No newline at end of file diff --git a/backend/risk_assessment_OpenAI.json b/backend/risk_assessment_OpenAI.json new file mode 100644 index 000000000..eec966b74 --- /dev/null +++ b/backend/risk_assessment_OpenAI.json @@ -0,0 +1,81 @@ +{ + "entityName": "OpenAI", + "entityType": "organization", + "riskAssessments": [ + { + "indicator": "Foreign State Influence", + "weight": 80, + "score": 3, + "explanation": "No direct evidence of foreign state influence was found in the provided data. However, given the global nature of AI research and potential geopolitical interests, a moderate risk score is assigned conservatively.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.32, + "weightedContribution": 0.96 + }, + { + "indicator": "Dual-Use Technology Exposure", + "weight": 70, + "score": 4, + "explanation": "AI technologies, including those developed by OpenAI, have significant dual-use potential, such as applications in both civilian and military contexts. This increases the risk of misuse or unintended consequences.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.28, + "weightedContribution": 1.12 + }, + { + "indicator": "Compliance with Canadian Research Security Policies", + "weight": 60, + "score": 2, + "explanation": "No evidence was found regarding OpenAI's compliance with Canadian research security policies. However, as a U.S.-based organization, it is likely subject to U.S. regulations, which may not fully align with Canadian policies.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.24, + "weightedContribution": 0.48 + }, + { + "indicator": "International Collaboration Patterns", + "weight": 50, + "score": 3, + "explanation": "OpenAI collaborates internationally, which can introduce risks related to intellectual property and security. However, no specific evidence of problematic collaborations was found in the provided data.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.2, + "weightedContribution": 0.6 + }, + { + "indicator": "Funding Sources Transparency", + "weight": 40, + "score": 2, + "explanation": "No evidence was found regarding the transparency of OpenAI's funding sources. A conservative score is assigned due to the lack of information.", + "sources": [ + "nil" + ], + "normalizedWeight": 0.16, + "weightedContribution": 0.32 + } + ], + "calculation": { + "totalWeight": 300, + "overallScore": 3.48, + "thresholdsApplied": { + "red": "overallScore >= 4.0", + "yellow": "2.5 <= overallScore < 4.0", + "blue": "overallScore < 2.5" + } + }, + "finalAssessment": { + "trafficLight": "Yellow", + "overallExplanation": "The overall risk assessment for OpenAI is moderate, primarily due to the dual-use nature of its technology and potential risks associated with international collaboration and compliance with Canadian policies." + }, + "analysis_metadata": { + "chunks_analyzed": 10, + "subgraph_nodes": 104, + "subgraph_relationships": 226, + "search_method": "unknown", + "best_match_score": 0.2617 + } +} \ No newline at end of file diff --git a/backend/run_tests.py b/backend/run_tests.py new file mode 100644 index 000000000..8f9b85886 --- /dev/null +++ b/backend/run_tests.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +""" +Test runner script for LLM Graph Builder Backend +Run all tests or specific test categories +""" + +import subprocess +import sys +import os +from pathlib import Path + +def run_tests(test_type="all", verbose=False): + """Run tests based on type""" + + # Change to backend directory + backend_dir = Path(__file__).parent + os.chdir(backend_dir) + + # Base pytest command + cmd = ["python3", "-m", "pytest", "tests/"] + + # Add verbose flag + if verbose: + cmd.append("-v") + + # Add specific test type filters + if test_type == "unit": + cmd.extend(["-m", "unit"]) + elif test_type == "integration": + cmd.extend(["-m", "integration"]) + elif test_type == "slow": + cmd.extend(["-m", "slow"]) + elif test_type == "monitoring": + cmd.extend(["tests/test_monitoring_integration.py", "-v"]) + elif test_type == "risk": + cmd.extend(["tests/test_risk_*.py", "-v"]) + elif test_type == "search": + cmd.extend(["tests/test_search*.py", "-v"]) + elif test_type == "extraction": + cmd.extend(["tests/test_*extraction*.py", "-v"]) + + # Add coverage if available + try: + import coverage + cmd.extend(["--cov=src", "--cov-report=html", "--cov-report=term"]) + except ImportError: + print("Coverage not available, install with: pip install coverage") + + print(f"๐Ÿš€ Running {test_type} tests...") + print(f"Command: {' '.join(cmd)}") + print("-" * 60) + + try: + result = subprocess.run(cmd, check=True) + print(f"\nโœ… Tests completed successfully!") + return True + except subprocess.CalledProcessError as e: + print(f"\nโŒ Tests failed with exit code {e.returncode}") + return False + except FileNotFoundError: + print("โŒ pytest not found. Install with: pip install pytest") + return False + +def main(): + """Main function to parse arguments and run tests""" + + if len(sys.argv) < 2: + print("Usage: python3 run_tests.py [--verbose]") + print("\nTest types:") + print(" all - Run all tests") + print(" unit - Run unit tests only") + print(" integration - Run integration tests only") + print(" slow - Run slow/performance tests only") + print(" monitoring - Run monitoring integration tests") + print(" risk - Run risk assessment tests") + print(" search - Run search-related tests") + print(" extraction - Run extraction-related tests") + print("\nOptions:") + print(" --verbose - Verbose output") + return + + test_type = sys.argv[1].lower() + verbose = "--verbose" in sys.argv + + # Validate test type + valid_types = ["all", "unit", "integration", "slow", "monitoring", "risk", "search", "extraction"] + if test_type not in valid_types: + print(f"โŒ Invalid test type: {test_type}") + print(f"Valid types: {', '.join(valid_types)}") + sys.exit(1) + + # Run tests + success = run_tests(test_type, verbose) + sys.exit(0 if success else 1) + +if __name__ == "__main__": + main() diff --git a/backend/score.py b/backend/score.py index 11209a0b4..525c719dc 100644 --- a/backend/score.py +++ b/backend/score.py @@ -2,6 +2,7 @@ from fastapi_health import health from fastapi.middleware.cors import CORSMiddleware from src.main import * +from src.main import analyze_risk_api from src.QA_integration import * from src.shared.common_fn import * from src.shared.llm_graph_builder_exception import LLMGraphBuilderException @@ -18,6 +19,8 @@ from sse_starlette.sse import EventSourceResponse from src.communities import create_communities from src.neighbours import get_neighbour_nodes +from src.risk_monitor import perform_risk_monitoring +from src.mcp_service import mcp_service import json from typing import List, Optional from google.oauth2.credentials import Credentials @@ -29,7 +32,7 @@ from Secweb.XContentTypeOptions import XContentTypeOptions from Secweb.XFrameOptions import XFrame from fastapi.middleware.gzip import GZipMiddleware -from src.ragas_eval import * +# from src.ragas_eval import * from starlette.types import ASGIApp, Receive, Scope, Send from langchain_neo4j import Neo4jGraph from starlette.middleware.sessions import SessionMiddleware @@ -103,7 +106,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send): app = FastAPI() app.add_middleware(XContentTypeOptions) app.add_middleware(XFrame, Option={'X-Frame-Options': 'DENY'}) -app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=5,paths=["/sources_list","/url/scan","/extract","/chat_bot","/chunk_entities","/get_neighbours","/graph_query","/schema","/populate_graph_schema","/get_unconnected_nodes_list","/get_duplicate_nodes","/fetch_chunktext","/schema_visualization"]) +app.add_middleware(CustomGZipMiddleware, minimum_size=1000, compresslevel=5,paths=["/sources_list","/url/scan","/extract","/chat_bot","/chunk_entities","/get_neighbours","/graph_query","/schema","/populate_graph_schema","/get_unconnected_nodes_list","/get_duplicate_nodes","/fetch_chunktext","/schema_visualization","/search_nodes","/get_subgraph","/search_and_get_subgraph","/diagnose_entities"]) app.add_middleware( CORSMiddleware, allow_origins=["*"], @@ -297,6 +300,36 @@ async def extract_knowledge_graph_from_file( logger.log_struct(result, "INFO") result.update(uri_latency) logging.info(f"extraction completed in {extract_api_time:.2f} seconds for file name {file_name}") + + # ๐Ÿš€ AUTOMATIC SUBGRAPH MONITORING - Trigger after successful document processing + try: + logging.info(f"Triggering automatic subgraph monitoring after document processing: {file_name}") + + # Import and use SubgraphMonitor + from src.subgraph_monitor import SubgraphMonitor + subgraph_monitor = SubgraphMonitor() + + # Monitor all entities for subgraph changes with risk assessment + monitoring_result = await subgraph_monitor.monitor_all_entities( + neo4j_uri=uri, + neo4j_username=userName, + neo4j_password=password, + neo4j_database=database, + model=model # Pass the model for LLM-based risk assessment + ) + + if monitoring_result.get("changes_detected", 0) > 0: + logging.info(f"๐Ÿšจ Subgraph changes detected: {monitoring_result['changes_detected']} entities with changes") + # Store monitoring result for potential alert generation + result['subgraph_monitoring'] = monitoring_result + else: + logging.info(f"โœ… No subgraph changes detected for monitored entities") + + except Exception as e: + logging.warning(f"Subgraph monitoring failed after document processing: {str(e)}") + # Don't fail the main extraction if monitoring fails + result['subgraph_monitoring_error'] = str(e) + return create_api_response('Success', data=result, file_source= source_type) except LLMGraphBuilderException as e: error_message = str(e) @@ -400,6 +433,36 @@ async def post_processing(uri=Form(None), userName=Form(None), password=Form(Non end = time.time() elapsed_time = end - start + + # ๐Ÿš€ AUTOMATIC SUBGRAPH MONITORING - Trigger after post-processing completion + try: + logging.info(f"Triggering automatic subgraph monitoring after post-processing tasks") + + # Import and use SubgraphMonitor + from src.subgraph_monitor import SubgraphMonitor + subgraph_monitor = SubgraphMonitor() + + # Monitor all entities for subgraph changes + monitoring_result = await subgraph_monitor.monitor_all_entities( + neo4j_uri=uri, + neo4j_username=userName, + neo4j_password=password, + neo4j_database=database, + model="openai_gpt_4o" # Default model for post-processing monitoring + ) + + if monitoring_result.get("changes_detected", 0) > 0: + logging.info(f"๐Ÿšจ Post-processing subgraph changes detected: {monitoring_result['changes_detected']} entities with changes") + # Add monitoring result to response + count_response.append({"subgraph_monitoring": monitoring_result}) + else: + logging.info(f"โœ… No subgraph changes detected after post-processing") + + except Exception as e: + logging.warning(f"Post-processing subgraph monitoring failed: {str(e)}") + # Don't fail the main post-processing if monitoring fails + count_response.append({"subgraph_monitoring_error": str(e)}) + json_obj = {'api_name': api_name, 'db_url': uri, 'userName':userName, 'database':database, 'logging_time': formatted_time(datetime.now(timezone.utc)), 'elapsed_api_time':f'{elapsed_time:.2f}','email':email} logger.log_struct(json_obj) return create_api_response('Success', data=count_response, message='All tasks completed successfully') @@ -1037,7 +1100,7 @@ async def backend_connection_configuration(): password= os.getenv('NEO4J_PASSWORD') gcs_file_cache = os.environ.get('GCS_FILE_CACHE') if all([uri, username, database, password]): - graph = Neo4jGraph() + graph = Neo4jGraph(url=uri, username=username, password=password, database=database) logging.info(f'login connection status of object: {graph}') if graph is not None: graph_connection = True @@ -1092,5 +1155,929 @@ async def get_schema_visualization(uri=Form(None), userName=Form(None), password finally: gc.collect() +@app.post("/search_nodes") +async def search_nodes_endpoint( + uri=Form(None), + userName=Form(None), + password=Form(None), + database=Form(None), + search_term=Form(), + node_type=Form("Person"), + max_results=Form(50), + prefer_vector=Form(True), + use_hybrid=Form(True) +): + """ + Search for nodes across all documents in the database with hybrid vector and fuzzy text search support. + """ + try: + start = time.time() + result = await asyncio.to_thread( + search_nodes_api, + uri=uri, + userName=userName, + password=password, + database=database, + search_term=search_term, + node_type=node_type, + max_results=int(max_results), + prefer_vector=str(prefer_vector).lower() == 'true', + use_hybrid=str(use_hybrid).lower() == 'true' + ) + end = time.time() + elapsed_time = end - start + json_obj = { + 'api_name': 'search_nodes', + 'db_url': uri, + 'userName': userName, + 'database': database, + 'search_term': search_term, + 'node_type': node_type, + 'max_results': max_results, + 'prefer_vector': prefer_vector, + 'use_hybrid': use_hybrid, + 'total_results': result.get('total_results', 0), + 'search_method': result.get('search_method', 'unknown'), + 'vector_available': result.get('search_metadata', {}).get('vector_available', False), + 'embedding_coverage': result.get('search_metadata', {}).get('embedding_coverage', 0), + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{elapsed_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + return create_api_response('Success', data=result, message=f"Search completed in {elapsed_time:.2f}s") + except Exception as e: + message = "Unable to search nodes" + error_message = str(e) + logging.exception(f'Exception in search_nodes: {error_message}') + return create_api_response('Failed', message=message, error=error_message) + finally: + gc.collect() + + +@app.post("/get_subgraph") +async def get_subgraph_endpoint( + uri=Form(None), + userName=Form(None), + password=Form(None), + database=Form(None), + node_id=Form(), + depth=Form(4), + max_nodes=Form(1000) +): + """ + Extract a subgraph from a specific node with configurable depth. + """ + try: + start = time.time() + result = await asyncio.to_thread( + get_subgraph_api, + uri=uri, + userName=userName, + password=password, + database=database, + node_id=node_id, + depth=int(depth), + max_nodes=int(max_nodes) + ) + end = time.time() + elapsed_time = end - start + json_obj = { + 'api_name': 'get_subgraph', + 'db_url': uri, + 'userName': userName, + 'database': database, + 'node_id': node_id, + 'depth': depth, + 'max_nodes': max_nodes, + 'nodes_count': len(result.get('nodes', [])), + 'relationships_count': len(result.get('relationships', [])), + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{elapsed_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + return create_api_response('Success', data=result, message=f"Subgraph extracted in {elapsed_time:.2f}s") + except Exception as e: + message = "Unable to extract subgraph" + error_message = str(e) + logging.exception(f'Exception in get_subgraph: {error_message}') + return create_api_response('Failed', message=message, error=error_message) + finally: + gc.collect() + + +@app.post("/search_and_get_subgraph") +async def search_and_get_subgraph_endpoint( + uri=Form(None), + userName=Form(None), + password=Form(None), + database=Form(None), + search_term=Form(), + node_type=Form("Person"), + depth=Form(4), + max_results=Form(10), + extract_best_match_only=Form(True) +): + """ + Search for nodes and extract their subgraphs in one operation. + """ + try: + start = time.time() + result = await asyncio.to_thread( + search_and_get_subgraph_api, + uri=uri, + userName=userName, + password=password, + database=database, + search_term=search_term, + node_type=node_type, + depth=int(depth), + max_results=int(max_results), + extract_best_match_only=str(extract_best_match_only).lower() == 'true' + ) + end = time.time() + elapsed_time = end - start + json_obj = { + 'api_name': 'search_and_get_subgraph', + 'db_url': uri, + 'userName': userName, + 'database': database, + 'search_term': search_term, + 'node_type': node_type, + 'depth': depth, + 'max_results': max_results, + 'extract_best_match_only': extract_best_match_only, + 'total_results': result.get('total_results', 0), + 'subgraphs_count': len(result.get('subgraphs', [])), + 'best_match': result.get('best_match', {}).get('node_name', 'None'), + 'best_match_score': result.get('best_match', {}).get('score', 'N/A'), + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{elapsed_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + return create_api_response('Success', data=result, message=f"Search and subgraph extraction completed in {elapsed_time:.2f}s") + except Exception as e: + message = "Unable to search and extract subgraphs" + error_message = str(e) + logging.exception(f'Exception in search_and_get_subgraph: {error_message}') + return create_api_response('Failed', message=message, error=error_message) + finally: + gc.collect() + +@app.post("/diagnose_entities") +async def diagnose_entities_endpoint( + uri=Form(None), + userName=Form(None), + password=Form(None), + database=Form(None) +): + """ + Diagnostic endpoint to check what entities exist in the database. + """ + try: + start = time.time() + result = await asyncio.to_thread( + diagnose_database_entities_api, + uri=uri, + userName=userName, + password=password, + database=database + ) + end = time.time() + elapsed_time = end - start + json_obj = { + 'api_name': 'diagnose_entities', + 'db_url': uri, + 'userName': userName, + 'database': database, + 'total_entity_types': result.get('total_entity_types', 0), + 'total_sample_entities': result.get('total_sample_entities', 0), + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{elapsed_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + return create_api_response('Success', data=result, message=f"Diagnosis completed in {elapsed_time:.2f}s") + except Exception as e: + message = "Unable to diagnose database entities" + error_message = str(e) + logging.exception(f'Exception in diagnose_entities: {error_message}') + return create_api_response('Failed', message=message, error=error_message) + finally: + gc.collect() + +@app.post("/analyze_risk") +async def analyze_risk_endpoint( + uri=Form(None), + userName=Form(None), + password=Form(None), + database=Form(None), + entity_name=Form(), + entity_type=Form(), + risk_indicators=Form(), # JSON string of risk indicators + depth=Form(4), + max_results=Form(10) +): + """ + Analyze research security risk of an entity based on graph data. + """ + try: + start = time.time() + + # Parse risk indicators JSON + try: + risk_indicators_dict = json.loads(risk_indicators) + except json.JSONDecodeError as e: + return create_api_response('Failed', message="Invalid risk indicators JSON format", error=str(e)) + + result = await asyncio.to_thread( + analyze_risk_api, + uri=uri, + userName=userName, + password=password, + database=database, + entity_name=entity_name, + entity_type=entity_type, + risk_indicators=risk_indicators_dict, + depth=int(depth), + max_results=int(max_results) + ) + + end = time.time() + elapsed_time = end - start + + json_obj = { + 'api_name': 'analyze_risk', + 'db_url': uri, + 'userName': userName, + 'database': database, + 'entity_name': entity_name, + 'entity_type': entity_type, + 'depth': depth, + 'max_results': max_results, + 'chunks_analyzed': result.get('analysis_metadata', {}).get('chunks_analyzed', 0), + 'subgraph_nodes': result.get('analysis_metadata', {}).get('subgraph_nodes', 0), + 'overall_score': result.get('calculation', {}).get('overallScore', 'N/A'), + 'traffic_light': result.get('finalAssessment', {}).get('trafficLight', 'N/A'), + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{elapsed_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + return create_api_response('Success', data=result, message=f"Risk analysis completed in {elapsed_time:.2f}s") + except Exception as e: + message = "Unable to analyze risk" + error_message = str(e) + logging.exception(f'Exception in analyze_risk: {error_message}') + return create_api_response('Failed', message=message, error=error_message) + finally: + gc.collect() + +@app.post("/list_documents") +async def list_documents( + uri=Form("neo4j+s://9379df68.databases.neo4j.io:7687"), + userName=Form("neo4j"), + password=Form(None), + database=Form("neo4j") +): + """List all available documents in the database for debugging.""" + try: + # Database connection setup + graph = create_graph_database_connection(uri, userName, password, database) + + # Query all documents + query = """ + MATCH (d:Document) + OPTIONAL MATCH (c:Chunk)-[:PART_OF]->(d) + WITH d, count(c) AS chunk_count + RETURN d.fileName AS filename, d.id AS id, d.size AS size, + d.created_date AS created_date, chunk_count + ORDER BY d.created_date DESC + LIMIT 20 + """ + + result = graph.query(query, {}) + return create_api_response('Success', data={ + "documents": result, + "total_count": len(result) + }) + + except Exception as e: + logging.error(f"Error listing documents: {str(e)}") + return create_api_response('Failed', message="Unable to list documents", error=str(e)) + +@app.post("/risk_monitor") +async def risk_monitor( + uri=Form("neo4j+s://9379df68.databases.neo4j.io:7687"), + userName=Form("neo4j"), + password=Form(None), + database=Form("neo4j"), + document_name=Form("[\"Abiy Ahmed\"]"), # JSON string of documents to monitor + monitored_names=Form("[\"Abiy Ahmed\"]"), # JSON string of names to monitor + risk_indicators=Form("[\"Dual-Use Technology Exposure\", \"Direct connections with foreign military entities\"]"), # JSON string of risk indicators + risk_threshold=Form(0.7), # Risk score threshold + model=Form("openai_gpt_4.1"), # LLM model to use + mode=Form("graph_vector_fulltext"), + email=Form(None) +): + """ + Monitor a document for specific names and risk indicators. + Returns information for creating risk alerts if any are detected. + """ + logging.info(f"Risk monitoring called at {datetime.now()}") + risk_monitor_start_time = time.time() + + try: + # Helper function to parse JSON arrays or comma-separated strings + def parse_list_input(input_str): + if not input_str: + return [] + try: + # Try to parse as JSON first + return json.loads(input_str) + except json.JSONDecodeError: + # If JSON parsing fails, treat as comma-separated string + return [item.strip() for item in input_str.split(',') if item.strip()] + + # Parse inputs (handles both JSON arrays and comma-separated strings) + document_names_list = parse_list_input(document_name) + monitored_names_list = parse_list_input(monitored_names) + risk_indicators_list = parse_list_input(risk_indicators) + + # Validate inputs + if not document_names_list: + return create_api_response('Failed', message="Document names are required", error="Missing document_name parameter") + + if not monitored_names_list and not risk_indicators_list: + return create_api_response('Failed', message="At least one of monitored_names or risk_indicators must be provided", error="Both parameters are empty") + + # Database connection setup + if mode == "graph": + graph = Neo4jGraph(url=uri, username=userName, password=password, database=database, sanitize=True, refresh_schema=True) + else: + graph = create_graph_database_connection(uri, userName, password, database) + + # Access control + graph_DB_dataAccess = graphDBdataAccess(graph) + write_access = graph_DB_dataAccess.check_account_access(database=database) + + # Core risk monitoring for multiple documents + all_results = [] + for doc_name in document_names_list: + result = await asyncio.to_thread( + perform_risk_monitoring, + graph=graph, + document_name=doc_name, + monitored_names=monitored_names_list, + risk_indicators=risk_indicators_list, + risk_threshold=float(risk_threshold), + model=model, + mode=mode + ) + logging.info(f"Risk monitoring result for {doc_name}: {result}") + all_results.append(result) + + # Combine results from all documents and format for frontend + all_alerts = [] + entities_checked = 0 + + for result in all_results: + if result.get("success"): + # Collect all alerts from all documents + all_alerts.extend(result.get("alerts", [])) + + # Track entities checked (count unique entities from alerts) + unique_entities = set() + for alert in result.get("alerts", []): + if alert.get("entity_name") and alert.get("entity_name") != "Unknown": + unique_entities.add(alert.get("entity_name")) + entities_checked += len(unique_entities) + + # Format response to match frontend MonitoringResult interface + combined_result = { + "timestamp": datetime.now().isoformat(), + "entities_checked": entities_checked, + "alerts": all_alerts, + "processing_time": 0 + } + result = combined_result + + # Performance tracking + total_call_time = time.time() - risk_monitor_start_time + logging.info(f"Total Response time is {total_call_time:.2f} seconds") + result["processing_time"] = round(total_call_time, 2) + + # Structured logging + json_obj = { + 'api_name': 'risk_monitor', + 'db_url': uri, + 'userName': userName, + 'database': database, + 'document_name': document_name, + 'monitored_names_count': len(monitored_names_list), + 'risk_indicators_count': len(risk_indicators_list), + 'risk_threshold': risk_threshold, + 'model': model, + 'mode': mode, + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{total_call_time:.2f}', + 'email': email + } + logger.log_struct(json_obj, "INFO") + + return create_api_response('Success', data=result) + + except Exception as e: + job_status = "Failed" + message = "Unable to perform risk monitoring" + error_message = str(e) + logging.exception(f'Exception in risk_monitor: {error_message}') + return create_api_response(job_status, message=message, error=error_message, data=mode) + finally: + gc.collect() + +@app.post("/monitoring/check_entities") +async def check_monitored_entities( + monitored_entities=Form("[]"), # JSON string of entity names to monitor + model=Form("openai_gpt_4o"), + uri=Form(None), # Neo4j connection URI + userName=Form(None), # Neo4j username + password=Form(None), # Neo4j password + database=Form(None) # Neo4j database +): + """ + Enhanced risk monitoring: Check if risk has increased for monitored entities. + This endpoint analyzes sub-graphs and generates LLM-based alerts. + Called after each document upload/URL scan. + """ + logging.info(f"Enhanced monitoring check called at {datetime.now()}") + monitoring_start_time = time.time() + + try: + # Parse monitored entities + try: + monitored_entities_list = json.loads(monitored_entities) if monitored_entities else [] + except json.JSONDecodeError as e: + return create_api_response('Failed', message="Invalid JSON format in monitored_entities", error=str(e)) + + # Validate inputs + if not monitored_entities_list: + return create_api_response('Failed', message="No monitored entities provided", error="monitored_entities parameter is empty") + + # Import and use MonitoringServicePG + from src.monitoring_service_pg import MonitoringServicePG + monitoring_service = MonitoringServicePG() + + # Setup Neo4j connection for sub-graph analysis + graph_connection = None + if uri and userName and password and database: + try: + from src.shared.common_fn import create_graph_database_connection + graph_connection = create_graph_database_connection(uri, userName, password, database) + logging.info(f"Neo4j connection established for enhanced monitoring") + except Exception as e: + logging.warning(f"Failed to establish Neo4j connection: {e}. Using basic monitoring.") + + # Check for risk changes with enhanced monitoring + result = await monitoring_service.check_entity_risk_changes(monitored_entities_list, model, graph_connection) + + # Performance tracking + total_call_time = time.time() - monitoring_start_time + logging.info(f"Monitoring check response time: {total_call_time:.2f} seconds") + + # Add timing info to result + if isinstance(result, dict): + result["processing_time"] = round(total_call_time, 2) + + # Structured logging + monitoring_type = "enhanced" if graph_connection else "basic" + json_obj = { + 'api_name': 'monitoring_check_entities', + 'monitoring_type': monitoring_type, + 'monitored_entities_count': len(monitored_entities_list), + 'model': model, + 'neo4j_connected': graph_connection is not None, + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{total_call_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + + return create_api_response('Success', data=result) + + except Exception as e: + job_status = "Failed" + message = "Unable to check monitored entities" + error_message = str(e) + logging.exception(f'Exception in check_monitored_entities: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() + +@app.post("/monitoring/subgraph_monitor") +async def subgraph_monitor_entities( + uri=Form(None), # Neo4j connection URI + userName=Form(None), # Neo4j username + password=Form(None), # Neo4j password + database=Form(None) # Neo4j database +): + """ + Automatic subgraph monitoring: Check all monitored entities for subgraph changes. + This endpoint is designed to be called after each document upload/processing. + """ + logging.info(f"Subgraph monitoring called at {datetime.now()}") + monitoring_start_time = time.time() + + try: + # Import and use SubgraphMonitor + from src.subgraph_monitor import SubgraphMonitor + subgraph_monitor = SubgraphMonitor() + + # Validate Neo4j connection parameters + if not all([uri, userName, password, database]): + return create_api_response('Failed', message="Neo4j connection parameters required", error="uri, userName, password, and database must be provided") + + # Monitor all entities for subgraph changes + result = await subgraph_monitor.monitor_all_entities( + neo4j_uri=uri, + neo4j_username=userName, + neo4j_password=password, + neo4j_database=database + ) + + # Performance tracking + total_call_time = time.time() - monitoring_start_time + logging.info(f"Subgraph monitoring response time: {total_call_time:.2f} seconds") + + # Add timing info to result + if isinstance(result, dict): + result["processing_time"] = round(total_call_time, 2) + + # Structured logging + json_obj = { + 'api_name': 'subgraph_monitor_entities', + 'neo4j_connected': True, + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{total_call_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + + return create_api_response('Success', data=result) + + except Exception as e: + job_status = "Failed" + message = "Unable to perform subgraph monitoring" + error_message = str(e) + logging.exception(f'Exception in subgraph_monitor_entities: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() + +@app.post("/monitoring/store_entities") +async def store_monitored_entities( + entities=Form() # JSON string of entities to store +): + """ + Store monitored entities in PostgreSQL database. + This allows the system to persist monitoring configuration. + """ + logging.info(f"Store monitored entities called at {datetime.now()}") + store_start_time = time.time() + + try: + # Parse entities JSON + try: + entities_list = json.loads(entities) if entities else [] + except json.JSONDecodeError as e: + return create_api_response('Failed', message="Invalid JSON format in entities", error=str(e)) + + # Validate inputs + if not entities_list: + return create_api_response('Failed', message="No entities provided", error="entities parameter is empty") + + # Import and use MonitoringServicePG + from src.monitoring_service_pg import MonitoringServicePG + monitoring_service = MonitoringServicePG() + + # Initialize schema + monitoring_service.initialize_monitoring_schema() + + # Store each entity + stored_entities = [] + for entity_data in entities_list: + try: + entity_id = monitoring_service.store_monitored_entity(entity_data) + stored_entities.append({ + "original": entity_data, + "stored_id": entity_id, + "status": "success" + }) + except Exception as e: + stored_entities.append({ + "original": entity_data, + "stored_id": None, + "status": "failed", + "error": str(e) + }) + + # Performance tracking + total_call_time = time.time() - store_start_time + logging.info(f"Store entities response time: {total_call_time:.2f} seconds") + + # Structured logging + json_obj = { + 'api_name': 'store_monitored_entities', + 'monitored_entities_count': len(entities_list), + 'successful_stores': len([e for e in stored_entities if e['status'] == 'success']), + 'failed_stores': len([e for e in stored_entities if e['status'] == 'failed']), + 'logging_time': formatted_time(datetime.now(timezone.utc)), + 'elapsed_api_time': f'{total_call_time:.2f}' + } + logger.log_struct(json_obj, "INFO") + + return create_api_response('Success', data={ + "entities_stored": len(stored_entities), + "successful": len([e for e in stored_entities if e['status'] == 'success']), + "failed": len([e for e in stored_entities if e['status'] == 'failed']), + "results": stored_entities, + "processing_time": round(total_call_time, 2) + }) + + except Exception as e: + job_status = "Failed" + message = "Unable to store monitored entities" + error_message = str(e) + logging.exception(f'Exception in store_monitored_entities: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + finally: + gc.collect() + +@app.get("/monitoring/entities") +async def get_monitored_entities(): + """ + Retrieve all monitored entities from PostgreSQL database. + """ + logging.info(f"Get monitored entities called at {datetime.now()}") + + try: + # Import and use MonitoringServicePG + from src.monitoring_service_pg import MonitoringServicePG + monitoring_service = MonitoringServicePG() + + # Get entities from database + entities = monitoring_service.get_monitored_entities_from_db() + + return create_api_response('Success', data=entities) + + except Exception as e: + job_status = "Failed" + message = "Unable to retrieve monitored entities" + error_message = str(e) + logging.exception(f'Exception in get_monitored_entities: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + +@app.get("/monitoring/alerts") +async def get_monitoring_alerts(): + """ + Get all monitoring alerts from PostgreSQL database. + """ + logging.info(f"Get monitoring alerts called at {datetime.now()}") + + try: + # Import and use MonitoringServicePG + from src.monitoring_service_pg import MonitoringServicePG + monitoring_service = MonitoringServicePG() + + # Get alerts from database + alerts = monitoring_service.get_monitoring_alerts() + + return create_api_response('Success', data=alerts) + + except Exception as e: + job_status = "Failed" + message = "Unable to get monitoring alerts" + error_message = str(e) + logging.exception(f'Exception in get_monitoring_alerts: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + +@app.post("/monitoring/alerts/{alert_id}/acknowledge") +async def acknowledge_monitoring_alert( + alert_id: str +): + """ + Acknowledge a monitoring alert, marking it as inactive. + """ + logging.info(f"Acknowledge monitoring alert called at {datetime.now()}") + + try: + # Import and use MonitoringServicePG + from src.monitoring_service_pg import MonitoringServicePG + monitoring_service = MonitoringServicePG() + + # Acknowledge alert in database + success = monitoring_service.acknowledge_alert(int(alert_id)) + + if success: + return create_api_response('Success', data={"message": f"Alert {alert_id} acknowledged successfully"}) + else: + return create_api_response('Failed', message="Alert not found or could not be acknowledged") + + except Exception as e: + job_status = "Failed" + message = "Unable to acknowledge monitoring alert" + error_message = str(e) + logging.exception(f'Exception in acknowledge_monitoring_alert: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + +@app.get("/monitoring/entities/{entity_id}/subgraph") +async def get_entity_subgraph( + entity_id: str, + uri=Form(None), # Neo4j connection URI + userName=Form(None), # Neo4j username + password=Form(None), # Neo4j password + database=Form(None) # Neo4j database +): + """ + Get subgraph information for a specific monitored entity. + """ + logging.info(f"Get entity subgraph called at {datetime.now()}") + + try: + # Import and use SubgraphMonitor + from src.subgraph_monitor import SubgraphMonitor + subgraph_monitor = SubgraphMonitor() + + # Get entity details first + from src.monitoring_service_pg import MonitoringServicePG + monitoring_service = MonitoringServicePG() + entity = monitoring_service.get_monitored_entity_by_id(int(entity_id)) + + if not entity: + return create_api_response('Failed', message="Entity not found", error=f"Entity with ID {entity_id} not found") + + # Validate Neo4j connection parameters + if not all([uri, userName, password, database]): + return create_api_response('Failed', message="Neo4j connection parameters required", error="uri, userName, password, and database must be provided") + + # Extract subgraph for the entity + from src.shared.common_fn import create_graph_database_connection + graph_connection = create_graph_database_connection(uri, userName, password, database) + + subgraph_data = subgraph_monitor.extract_entity_subgraph(entity["name"], graph_connection) + + if subgraph_data: + return create_api_response('Success', data={ + "entity": entity, + "subgraph": subgraph_data + }) + else: + return create_api_response('Failed', message="Could not extract subgraph", error="No subgraph data found for entity") + + except Exception as e: + job_status = "Failed" + message = "Unable to get entity subgraph" + error_message = str(e) + logging.exception(f'Exception in get_entity_subgraph: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + +@app.delete("/monitoring/entities/{entity_id}") +async def remove_monitored_entity( + entity_id: str +): + """ + Remove a monitored entity from PostgreSQL database. + """ + logging.info(f"Remove monitored entity called at {datetime.now()}") + + try: + # Import and use MonitoringServicePG + from src.monitoring_service_pg import MonitoringServicePG + monitoring_service = MonitoringServicePG() + + # Remove entity from database + success = monitoring_service.remove_monitored_entity(entity_id) + + if success: + return create_api_response('Success', data={"message": f"Entity {entity_id} removed successfully"}) + else: + return create_api_response('Failed', message="Entity not found or could not be removed") + + except Exception as e: + job_status = "Failed" + message = "Unable to remove monitored entity" + error_message = str(e) + logging.exception(f'Exception in remove_monitored_entity: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + +@app.post("/mcp/generate_chart") +async def generate_chart_with_mcp( + query=Form(""), # Natural language query + uri=Form(None), # Neo4j URI - will use env var if not provided + userName=Form(None), # Neo4j username - will use env var if not provided + password=Form(None), # Neo4j password - will use env var if not provided + database=Form(None), # Neo4j database - will use env var if not provided +): + """ + Generate charts from natural language queries using MCP Neo4j integration. + The LLM will infer the appropriate chart type based on the query. + + Args: + query: Natural language description of what data to visualize + uri: Neo4j connection URI + userName: Neo4j username + password: Neo4j password + database: Neo4j database name + + Returns: + Chart data in format suitable for frontend visualization + """ + logging.info(f"MCP chart generation called at {datetime.now()}") + chart_start_time = time.time() + + try: + # Validate required parameters + if not query.strip(): + return create_api_response('Failed', message="Query is required", error="Missing query parameter") + + # Get Neo4j configuration from parameters or environment variables + if not uri: + uri = os.getenv("NEO4J_URI") + if not userName: + userName = os.getenv("NEO4J_USERNAME", "neo4j") + if not password: + password = os.getenv("NEO4J_PASSWORD") + if not database: + database = os.getenv("NEO4J_DATABASE", "neo4j") + + # Validate Neo4j configuration + if not uri: + return create_api_response('Failed', message="Neo4j URI is required", error="Missing uri parameter or NEO4J_URI environment variable") + if not password: + return create_api_response('Failed', message="Neo4j password is required", error="Missing password parameter or NEO4J_PASSWORD environment variable") + + # Get OpenAI API key from environment + openai_api_key = os.getenv("OPENAI_API_KEY") + if not openai_api_key: + return create_api_response('Failed', message="OpenAI API key is required", error="Missing OPENAI_API_KEY environment variable") + + + # Neo4j configuration + neo4j_config = { + "uri": uri, + "username": userName, + "password": password, + "database": database + } + + # Start MCP server if not already running + if not mcp_service.mcp_process or mcp_service.mcp_process.poll() is not None: + logging.info("Starting MCP server...") + if not await mcp_service.start_mcp_server(neo4j_config): + return create_api_response('Failed', message="Failed to start MCP server", error="MCP server startup failed") + + # Process the natural language query + logging.info(f"Processing query: {query}") + result = await mcp_service.process_natural_language_query( + query=query, + openai_api_key=openai_api_key, + model="gpt-4" # Use default model from environment + ) + + if result["success"]: + chart_end_time = time.time() + processing_time = chart_end_time - chart_start_time + + response_data = { + "chartData": result["chartData"], + "chartConfig": result["chartConfig"], + "type": result.get("chartType", "bar") + } + + return create_api_response( + 'Success', + message=f"Chart generated successfully in {processing_time:.2f} seconds", + data=response_data + ) + else: + return create_api_response( + 'Failed', + message="Failed to generate chart", + error=result.get("error", "Unknown error occurred") + ) + + except Exception as e: + job_status = "Failed" + message = "Unable to generate chart" + error_message = str(e) + logging.exception(f'Exception in generate_chart_with_mcp: {error_message}') + return create_api_response(job_status, message=message, error=error_message) + +@app.post("/mcp/stop_server") +async def stop_mcp_server(): + """ + Stop the MCP Neo4j server. + """ + try: + await mcp_service.stop_mcp_server() + return create_api_response('Success', message="MCP server stopped successfully") + except Exception as e: + return create_api_response('Failed', message="Failed to stop MCP server", error=str(e)) + if __name__ == "__main__": uvicorn.run(app) \ No newline at end of file diff --git a/backend/simple_debug.py b/backend/simple_debug.py new file mode 100644 index 000000000..11ec8389b --- /dev/null +++ b/backend/simple_debug.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +""" +Simple debug script to check database contents +""" + +import os +import sys + +def simple_debug(): + """Simple database debugging without complex imports.""" + print("๐Ÿ” Simple Database Debug") + print("=" * 50) + + # Check environment variables + print("\n๐Ÿ“‹ Environment Check:") + neo4j_uri = os.environ.get('NEO4J_URI', 'Not set') + neo4j_username = os.environ.get('NEO4J_USERNAME', 'Not set') + neo4j_database = os.environ.get('NEO4J_DATABASE', 'Not set') + + print(f" NEO4J_URI: {neo4j_uri}") + print(f" NEO4J_USERNAME: {neo4j_username}") + print(f" NEO4J_DATABASE: {neo4j_database}") + + # Check if we can access the database connection from score.py + print("\n๐Ÿ”Œ Database Connection Check:") + try: + # Try to import the database connection function + sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + from src.shared.common_fn import create_graph_database_connection + print(" โœ… Database connection function imported successfully") + + # Try to create a connection + uri = "neo4j+s://9379df68.databases.neo4j.io:7687" + username = "neo4j" + password = "your_password_here" # You need to update this + + print(f" ๐Ÿ”— Attempting connection to: {uri}") + print(f" ๐Ÿ‘ค Username: {username}") + print(f" ๐Ÿ—„๏ธ Database: {database}") + print(" โš ๏ธ Note: Update password in script to test connection") + + except ImportError as e: + print(f" โŒ Import error: {e}") + print(" ๐Ÿ’ก This suggests missing dependencies") + except Exception as e: + print(f" โŒ Other error: {e}") + + # Check what files exist in the database directory + print("\n๐Ÿ“ File System Check:") + current_dir = os.getcwd() + print(f" Current directory: {current_dir}") + + # Check for database-related files + db_files = [] + for root, dirs, files in os.walk(current_dir): + for file in files: + if any(keyword in file.lower() for keyword in ['neo4j', 'database', 'graph', 'chunk']): + db_files.append(os.path.join(root, file)) + + if db_files: + print(f" Found {len(db_files)} database-related files:") + for file in db_files[:10]: # Show first 10 + print(f" - {file}") + if len(db_files) > 10: + print(f" ... and {len(db_files) - 10} more") + else: + print(" No obvious database files found") + + # Check for environment setup + print("\nโš™๏ธ Environment Setup:") + python_path = sys.executable + print(f" Python executable: {python_path}") + + # Check if we're in a virtual environment + if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): + print(" โœ… Running in virtual environment") + else: + print(" โŒ Not running in virtual environment") + + print("\n๐Ÿ’ก Next Steps:") + print(" 1. Update the password in the script") + print(" 2. Install required dependencies: pip install langchain-neo4j") + print(" 3. Run the full debug script") + print(" 4. Check if the document 'Abiy_Ahmed' exists and has chunks") + +if __name__ == "__main__": + simple_debug() diff --git a/backend/src/constants/chart_prompts.py b/backend/src/constants/chart_prompts.py new file mode 100644 index 000000000..57b1efb3d --- /dev/null +++ b/backend/src/constants/chart_prompts.py @@ -0,0 +1,155 @@ +""" +Chart generation prompts for MCP Neo4j integration +Contains LLM prompts for generating Cypher queries and formatting chart data +""" + +def create_cypher_query_prompt(query: str, schema_info: dict = None) -> str: + """Create a prompt for generating Cypher queries from natural language""" + schema_text = "" + if schema_info: + labels = ", ".join(schema_info.get('labels', [])) + relationships = ", ".join(schema_info.get('relationship_types', [])) + properties = ", ".join(schema_info.get('property_keys', [])) + + schema_text = f""" +Database Schema: +- Node Labels: {labels} +- Relationship Types: {relationships} +- Property Keys: {properties} + +""" + + return f"""{schema_text}User Question: {query} + +IMPORTANT RULES FOR CYPHER QUERIES: +1. Use READ-ONLY operations (MATCH, RETURN, WITH, WHERE, ORDER BY, etc.) +2. NO write operations (CREATE, DELETE, SET, REMOVE, MERGE, etc.) +3. Return data in a format suitable for visualization +4. Use appropriate LIMIT to balance performance and completeness +5. Complex queries are allowed - use WITH, aggregation functions, and subqueries as needed +6. For multiple data series, use UNION ALL to combine results +7. Use meaningful column names that describe the data + +Based on the user's question, generate an appropriate Cypher query that will return data suitable for visualization. + +EXAMPLES OF FLEXIBLE QUERIES: + +Simple counts: +MATCH (n) RETURN labels(n)[0] as NodeType, count(*) as Count ORDER BY Count DESC + +Complex aggregations: +MATCH (n)-[r]->(m) +WITH type(r) as RelationshipType, count(r) as Count +RETURN RelationshipType, Count ORDER BY Count DESC + +Multiple data series: +MATCH (n:Person) RETURN 'Person' as Category, count(n) as Count +UNION ALL +MATCH (n:Organization) RETURN 'Organization' as Category, count(n) as Count + +Time-based analysis: +MATCH (n) +WHERE n.created_at IS NOT NULL +RETURN date(n.created_at) as Date, count(n) as Count +ORDER BY Date + +Relationship analysis: +MATCH (a)-[r]->(b) +RETURN labels(a)[0] as SourceType, type(r) as RelationshipType, labels(b)[0] as TargetType, count(r) as Count +ORDER BY Count DESC + +Return only the Cypher query, no explanations or markdown formatting.""" + +def create_chart_formatting_prompt(query: str, raw_data: list) -> str: + """Create a prompt for generating structured chart data and config""" + import json + raw_data_json = json.dumps(raw_data, indent=2) + + return f"""You are a helpful assistant that works with Neo4j databases. You can help with schema discovery, running Cypher queries, and data manipulation. + +User requirement: {query} + +IMPORTANT: Analyze the user requirement to determine the most appropriate chart type: +- Use "pie" for: pie charts, pie chart, proportions, percentages, parts of a whole, distribution +- Use "bar" for: bar charts, bar chart, comparisons, categories, rankings, counts +- Use "line" for: line charts, line chart, trends, time series, changes over time, progression + +Given the user requirement and the data below, return a JSON object that would be used for data visualization. It should include the chartConfig and the chartData in a single object. Feel free to pick appropriate colors and labels for your chartConfig. + +IMPORTANT: +- For single-series data (like counts by category), use the "name" and "value" format in chartData +- For multi-series data, use the appropriate format shown in examples +- For time-series data, use "date" or "time" as the x-axis and numeric values for y-axis +- For relationship data, include both source and target information +- Use meaningful labels that clearly describe what the data represents + +DATA: {raw_data_json} + +Examples of responses: + +For pie charts: +{{ + "chartConfig": {{ + "Desktop": {{ "label": "Desktop", "color": "#2563eb" }}, + "Mobile": {{ "label": "Mobile", "color": "#60a5fa" }} + }}, + "chartData": [ + {{ "name": "Desktop", "value": 186 }}, + {{ "name": "Mobile", "value": 80 }} + ], + "type": "pie" +}} + +For bar charts (single series): +{{ + "chartConfig": {{ + "Desktop": {{ "label": "Desktop", "color": "#2563eb" }}, + "Mobile": {{ "label": "Mobile", "color": "#60a5fa" }} + }}, + "chartData": [ + {{ "name": "Desktop", "value": 186 }}, + {{ "name": "Mobile", "value": 80 }} + ], + "type": "bar" +}} + +For bar charts (multi-series with categories): +{{ + "chartConfig": {{ + "sales": {{ "label": "Sales", "color": "#2563eb" }}, + "revenue": {{ "label": "Revenue", "color": "#60a5fa" }} + }}, + "chartData": [ + {{ "name": "Q1", "sales": 186, "revenue": 80 }}, + {{ "name": "Q2", "sales": 305, "revenue": 200 }} + ], + "type": "bar" +}} + +For bar charts (multi-series): +{{ + "chartConfig": {{ + "desktop": {{ "label": "Desktop", "color": "#2563eb" }}, + "mobile": {{ "label": "Mobile", "color": "#60a5fa" }} + }}, + "chartData": [ + {{ "month": "January", "desktop": 186, "mobile": 80 }}, + {{ "month": "February", "desktop": 305, "mobile": 200 }} + ], + "type": "bar" +}} + +For line charts: +{{ + "chartConfig": {{ + "sales": {{ "label": "Sales", "color": "#2563eb" }}, + "revenue": {{ "label": "Revenue", "color": "#60a5fa" }} + }}, + "chartData": [ + {{ "month": "January", "sales": 186, "revenue": 80 }}, + {{ "month": "February", "sales": 305, "revenue": 200 }} + ], + "type": "line" +}} + +Return ONLY valid JSON with no explanations or markdown formatting. Use the actual data provided above and choose the most appropriate chart type based on the user requirement.""" diff --git a/backend/src/constants/risk_monitoring_prompts.py b/backend/src/constants/risk_monitoring_prompts.py new file mode 100644 index 000000000..66fbb9361 --- /dev/null +++ b/backend/src/constants/risk_monitoring_prompts.py @@ -0,0 +1,69 @@ +""" +Constants for Risk Monitoring System +Contains LLM prompts and risk level definitions +""" + +RISK_MONITORING_PROMPTS = { + "ENTITY_RISK_ALERTS": """ + You are a risk monitoring specialist. Analyze the document content for specific entities and risk indicators to generate alerts. + + MONITORED ENTITIES: {monitored_names} + RISK INDICATORS: {risk_indicators} + RISK THRESHOLD: {risk_threshold} + + ANALYSIS APPROACH: + 1. For each monitored entity, check if they are mentioned in the document + 2. For each mentioned entity, analyze their activities, connections, and context + 3. Match entity activities to risk indicators using semantic understanding + 4. Generate alerts for ANY reasonable connection between entity and risk indicator + 5. DO NOT skip any indicators - check ALL of them for each entity to be sure we make accurate alerts based on document content. + + RISK INDICATOR MATCHING RULES: + - Use semantic understanding, not just exact word matches + - Consider related concepts, synonyms, and contextual connections + - Technology-related activities โ†’ "Technology", "Dual-Use Technology Exposure" + - Business/Corporate activities โ†’ "Business", "Organizational structure transparency assessment" + - Government connections โ†’ "Foreign government control indicators", "Foreign government interference indicators" + - Financial activities โ†’ "Financial", "Conflict of interest detection" + - Military/Defense connections โ†’ "Direct/Indirect connections with foreign military entities" + - Research activities โ†’ "Unauthorized knowledge transfer risks", "Intellectual property theft connections" + + CONSISTENCY REQUIREMENTS: + - Be consistent in your analysis approach + - If an entity has technology connections, flag technology-related indicators + - If an entity has business connections, flag business-related indicators + - Use a risk score of 0.3-0.5 for general connections, 0.6-0.8 for specific connections, 0.9+ for direct connections + + Document Content: + {document_content} + + Generate alerts for entities that: + - Are mentioned in the document + - Have activities/connections that relate to any risk indicator + - Have a risk score >= {risk_threshold} + + REMINDER: You must systematically check EVERY risk indicator for EVERY entity. Do not stop early! + + Respond in this JSON format: + {{ + "alerts": [ + {{ + "entity_name": "John Doe", + "risk_indicator": "Technology", + "title": "Technology Risk Alert for John Doe", + "description": "John Doe mentioned in connection with technology-related activities: [specific details from document]", + "risk_score": 0.7, + "evidence": "Specific text from document showing the connection" + }} + ] + }} + + If no entities are found with risk indicators, return: {{"alerts": []}} + """ +} + +RISK_LEVELS = { + "LOW": {"min": 0.0, "max": 0.3, "color": "green", "action": "Monitor"}, + "MEDIUM": {"min": 0.3, "max": 0.7, "color": "yellow", "action": "Review"}, + "HIGH": {"min": 0.7, "max": 1.0, "color": "red", "action": "Immediate Action Required"} +} diff --git a/backend/src/database.py b/backend/src/database.py new file mode 100644 index 000000000..127a423b5 --- /dev/null +++ b/backend/src/database.py @@ -0,0 +1,144 @@ +""" +PostgreSQL database configuration and connection management +""" + +import os +import psycopg2 +from psycopg2.extras import RealDictCursor +from psycopg2.pool import SimpleConnectionPool +from contextlib import contextmanager +import logging +from typing import Optional, Dict, Any, List +from dotenv import load_dotenv + +# Load environment variables from .env file +load_dotenv() + +logger = logging.getLogger(__name__) + +class DatabaseManager: + def __init__(self): + self.pool = None + self._init_pool() + + def _init_pool(self): + """Initialize connection pool""" + try: + # Get database URL from environment + database_url = os.getenv("DATABASE_URL") + + if database_url: + # Parse DATABASE_URL format: postgresql://user:password@host:port/dbname + self.pool = SimpleConnectionPool( + minconn=1, + maxconn=10, + dsn=database_url + ) + logger.info("Database pool initialized with DATABASE_URL") + else: + # Fallback to individual environment variables + host = os.getenv("POSTGRES_HOST", "localhost") + port = os.getenv("POSTGRES_PORT", "5432") + database = os.getenv("POSTGRES_DB", "monitoring_db") + user = os.getenv("POSTGRES_USER", "postgres") + password = os.getenv("POSTGRES_PASSWORD", "password") + + self.pool = SimpleConnectionPool( + minconn=1, + maxconn=10, + host=host, + port=port, + database=database, + user=user, + password=password + ) + logger.info(f"Database pool initialized with host: {host}, database: {database}") + + except Exception as e: + logger.error(f"Failed to initialize database pool: {e}") + self.pool = None + + @contextmanager + def get_connection(self): + """Get a database connection from the pool""" + conn = None + try: + if self.pool: + conn = self.pool.getconn() + yield conn + else: + raise Exception("Database pool not initialized") + except Exception as e: + logger.error(f"Error getting database connection: {e}") + raise + finally: + if conn and self.pool: + self.pool.putconn(conn) + + def execute_query(self, query: str, params: Optional[tuple] = None) -> List[Dict[str, Any]]: + """Execute a SELECT query and return results as list of dicts""" + try: + with self.get_connection() as conn: + with conn.cursor(cursor_factory=RealDictCursor) as cursor: + cursor.execute(query, params) + results = cursor.fetchall() + return [dict(row) for row in results] + except Exception as e: + logger.error(f"Error executing query: {e}") + logger.error(f"Query: {query}") + logger.error(f"Params: {params}") + raise + + def execute_command(self, command: str, params: Optional[tuple] = None) -> int: + """Execute an INSERT/UPDATE/DELETE command and return affected row count""" + try: + with self.get_connection() as conn: + with conn.cursor() as cursor: + cursor.execute(command, params) + conn.commit() + return cursor.rowcount + except Exception as e: + logger.error(f"Error executing command: {e}") + logger.error(f"Command: {command}") + logger.error(f"Params: {params}") + raise + + def execute_many(self, command: str, params_list: List[tuple]) -> int: + """Execute multiple commands with different parameters""" + try: + with self.get_connection() as conn: + with conn.cursor() as cursor: + cursor.executemany(command, params_list) + conn.commit() + return cursor.rowcount + except Exception as e: + logger.error(f"Error executing many commands: {e}") + raise + + def execute_insert_returning(self, command: str, params: Optional[tuple] = None) -> List[Dict[str, Any]]: + """Execute an INSERT/UPDATE command with RETURNING clause and return results""" + try: + with self.get_connection() as conn: + with conn.cursor(cursor_factory=RealDictCursor) as cursor: + cursor.execute(command, params) + conn.commit() + results = cursor.fetchall() + return [dict(row) for row in results] + except Exception as e: + logger.error(f"Error executing insert with returning: {e}") + logger.error(f"Command: {command}") + logger.error(f"Params: {params}") + raise + + def close(self): + """Close the connection pool""" + if self.pool: + self.pool.closeall() + logger.info("Database pool closed") + +# Global database manager instance +db_manager = DatabaseManager() + +def get_db() -> DatabaseManager: + """Get the global database manager instance""" + return db_manager diff --git a/backend/src/graphDB_dataAccess.py b/backend/src/graphDB_dataAccess.py index 77cc9e592..02ec32d16 100644 --- a/backend/src/graphDB_dataAccess.py +++ b/backend/src/graphDB_dataAccess.py @@ -70,7 +70,7 @@ def create_source_node(self, obj_source_node:sourceNode): except Exception as e: error_message = str(e) logging.info(f"error_message = {error_message}") - self.update_exception_db(self, obj_source_node.file_name, error_message) + self.update_exception_db(obj_source_node.file_name, error_message) raise Exception(error_message) def update_source_node(self, obj_source_node:sourceNode): diff --git a/backend/src/graph_query.py b/backend/src/graph_query.py index f8054061f..800087482 100644 --- a/backend/src/graph_query.py +++ b/backend/src/graph_query.py @@ -53,10 +53,14 @@ def execute_query(driver, query,document_names,doc_limit=None): logging.error(error_message, exc_info=True) -def process_node(node): +def process_node(node, preserve_text=False): """ Processes a node from a Neo4j database, extracting its ID, labels, and properties, - while omitting certain properties like 'embedding' and 'text'. + while omitting certain properties like 'embedding' and 'text' (unless preserve_text=True). + + Args: + node: Neo4j node object + preserve_text: If True, preserve text content (useful for chunk extraction) Returns: dict: A dictionary with the node's element ID, labels, and other properties, @@ -76,7 +80,8 @@ def process_node(node): # logging.info(f"Processing node with element ID: {node.element_id}") for key in node: - if key in ["embedding", "text", "summary"]: + # Skip embedding and summary, but preserve text if requested + if key in ["embedding", "summary"] or (key == "text" and not preserve_text): continue value = node.get(key) if isinstance(value, time.DateTime): @@ -278,3 +283,629 @@ def visualize_schema(uri, userName, password, database): finally: if driver: driver.close() + +# Search and retreive nodes +def check_vector_availability(driver, node_type="Person"): + """ + Check if vector embeddings exist for the specified node type. + + Args: + driver: Neo4j driver instance + node_type (str): The type of node to check + + Returns: + dict: Contains availability info and sample data + """ + try: + # Check if any nodes of this type have embeddings + check_query = f""" + MATCH (n:__Entity__) + WHERE '{node_type}' IN labels(n) + WITH count(n) as total_nodes, + count(CASE WHEN n.embedding IS NOT NULL THEN n END) as nodes_with_embeddings + RETURN total_nodes, nodes_with_embeddings, + CASE WHEN nodes_with_embeddings > 0 THEN true ELSE false END as has_embeddings + """ + + records, summary, keys = driver.execute_query(check_query) + + if records: + result = records[0] + return { + "has_embeddings": result["has_embeddings"], + "total_nodes": result["total_nodes"], + "nodes_with_embeddings": result["nodes_with_embeddings"], + "embedding_coverage": result["nodes_with_embeddings"] / result["total_nodes"] if result["total_nodes"] > 0 else 0 + } + return {"has_embeddings": False, "total_nodes": 0, "nodes_with_embeddings": 0, "embedding_coverage": 0} + + except Exception as e: + logging.error(f"Error checking vector availability: {str(e)}") + return {"has_embeddings": False, "total_nodes": 0, "nodes_with_embeddings": 0, "embedding_coverage": 0} + +def search_nodes_with_vector(driver, search_term, node_type="Person", max_results=50, similarity_threshold=0.3): + """ + Search for nodes using vector similarity with improved semantic matching. + + Args: + driver: Neo4j driver instance + search_term (str): The search term + node_type (str): The type of node to search for + max_results (int): Maximum number of results + similarity_threshold (float): Minimum similarity score (lowered for better semantic matching) + + Returns: + list: Matching nodes with similarity scores + """ + try: + # Import embedding function here to avoid circular imports + from src.shared.common_fn import load_embedding_model + import os + + # Load embedding model + embedding_model = os.getenv('EMBEDDING_MODEL', 'all-MiniLM-L6-v2') + embeddings, dimension = load_embedding_model(embedding_model) + + # Create embedding for search term + search_embedding = embeddings.embed_query(search_term) + + # Enhanced vector similarity search query with better semantic matching + vector_search_query = f""" + MATCH (n:__Entity__) + WHERE '{node_type}' IN labels(n) + AND n.embedding IS NOT NULL + WITH n, vector.similarity.cosine(n.embedding, $search_embedding) AS similarity + WHERE similarity > $similarity_threshold + RETURN n, similarity + ORDER BY similarity DESC + LIMIT $max_results + """ + + records, summary, keys = driver.execute_query( + vector_search_query, + search_embedding=search_embedding, + similarity_threshold=similarity_threshold, + max_results=max_results + ) + + matching_nodes = [] + for record in records: + node = record["n"] + similarity = record["similarity"] + node_element = process_node(node) + node_element["similarity_score"] = round(similarity, 4) + node_element["search_method"] = "vector_similarity" + matching_nodes.append(node_element) + + return matching_nodes + + except Exception as e: + logging.error(f"Error in vector similarity search: {str(e)}") + return [] + +def search_nodes_with_fuzzy_text(driver, search_term, node_type="Person", max_results=50): + """ + Search for nodes using fuzzy text matching for better name variations. + + Args: + driver: Neo4j driver instance + search_term (str): The search term + node_type (str): The type of node to search for + max_results (int): Maximum number of results + + Returns: + list: Matching nodes + """ + try: + # Split search term into words for better matching + search_words = search_term.lower().split() + + # Create a more flexible text search query + fuzzy_search_query = f""" + MATCH (n:__Entity__) + WHERE '{node_type}' IN labels(n) + WITH n, toLower(n.id) as node_id_lower + WITH n, node_id_lower, + size([word IN $search_words WHERE node_id_lower CONTAINS word]) as word_matches, + size($search_words) as total_words + WHERE word_matches > 0 + WITH n, word_matches, total_words, + toFloat(word_matches) / toFloat(total_words) as match_ratio + WHERE match_ratio >= 0.5 // At least 50% of words must match + RETURN n, match_ratio + ORDER BY match_ratio DESC, n.id + LIMIT $max_results + """ + + records, summary, keys = driver.execute_query( + fuzzy_search_query, + search_words=search_words, + max_results=max_results + ) + + matching_nodes = [] + for record in records: + node = record["n"] + match_ratio = record["match_ratio"] + node_element = process_node(node) + node_element["match_ratio"] = round(match_ratio, 4) + node_element["search_method"] = "fuzzy_text" + matching_nodes.append(node_element) + + return matching_nodes + + except Exception as e: + logging.error(f"Error in fuzzy text search: {str(e)}") + return [] + +def search_nodes_with_text(driver, search_term, node_type="Person", max_results=50): + """ + Search for nodes using text matching (original method). + + Args: + driver: Neo4j driver instance + search_term (str): The search term + node_type (str): The type of node to search for + max_results (int): Maximum number of results + + Returns: + list: Matching nodes + """ + try: + search_query = f""" + MATCH (n:__Entity__) + WHERE '{node_type}' IN labels(n) + AND toLower(n.id) CONTAINS toLower($search_term) + RETURN n + LIMIT $max_results + """ + + records, summary, keys = driver.execute_query( + search_query, + search_term=search_term, + max_results=max_results + ) + + matching_nodes = [] + for record in records: + node = record["n"] + node_element = process_node(node) + node_element["search_method"] = "text_match" + matching_nodes.append(node_element) + + return matching_nodes + + except Exception as e: + logging.error(f"Error in text search: {str(e)}") + return [] + +def search_nodes(uri, username, password, database, search_term, node_type="Person", max_results=50, prefer_vector=True, use_hybrid=True): + """ + Enhanced search function with hybrid approach combining vector and fuzzy text search. + + Args: + uri (str): The URI for the Neo4j database. + username (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + search_term (str): The search term to look for in node properties. + node_type (str): The type of node to search for (default: "Person"). + max_results (int): Maximum number of results to return. + prefer_vector (bool): Whether to prefer vector search over text search when both are available. + use_hybrid (bool): Whether to use hybrid search combining vector and fuzzy text. + + Returns: + dict: Contains matching nodes with their properties and search method info. + """ + driver = None + try: + logging.info(f"Starting enhanced node search for term: '{search_term}' in node type: '{node_type}' (hybrid={use_hybrid})") + driver = get_graphDB_driver(uri, username, password, database) + + # Step 1: Check vector availability + vector_info = check_vector_availability(driver, node_type) + logging.info(f"Vector availability check: {vector_info}") + + # Step 2: Perform hybrid search if enabled and vectors are available + if use_hybrid and vector_info["has_embeddings"] and prefer_vector: + logging.info("Using hybrid search (vector + fuzzy text)") + + # Get vector search results + vector_nodes = search_nodes_with_vector(driver, search_term, node_type, max_results) + + # Get fuzzy text search results + fuzzy_nodes = search_nodes_with_fuzzy_text(driver, search_term, node_type, max_results) + + # Combine and deduplicate results with adaptive scoring + combined_nodes = combine_search_results(vector_nodes, fuzzy_nodes, max_results, vector_info["embedding_coverage"]) + + search_method = "hybrid_vector_fuzzy" + + # Step 3: Fallback to single method search + else: + if vector_info["has_embeddings"] and prefer_vector: + combined_nodes = search_nodes_with_vector(driver, search_term, node_type, max_results) + search_method = "vector_similarity" + logging.info(f"Using vector similarity search (coverage: {vector_info['embedding_coverage']:.2%})") + else: + combined_nodes = search_nodes_with_fuzzy_text(driver, search_term, node_type, max_results) + if not combined_nodes: + combined_nodes = search_nodes_with_text(driver, search_term, node_type, max_results) + search_method = "fuzzy_text" if combined_nodes and combined_nodes[0].get("search_method") == "fuzzy_text" else "text_match" + logging.info("Using text-based search") + + logging.info(f"Found {len(combined_nodes)} matching nodes for search term: '{search_term}'") + + return { + "search_term": search_term, + "node_type": node_type, + "total_results": len(combined_nodes), + "nodes": combined_nodes, + "search_method": search_method, + "vector_info": vector_info, + "search_metadata": { + "prefer_vector": prefer_vector, + "use_hybrid": use_hybrid, + "vector_available": vector_info["has_embeddings"], + "embedding_coverage": vector_info["embedding_coverage"] + } + } + + except Exception as e: + logging.error(f"An error occurred in search_nodes. Error: {str(e)}") + raise Exception(f"An error occurred in search_nodes. Please check the logs for more details.") from e + finally: + if driver: + driver.close() + +def combine_search_results(vector_nodes, fuzzy_nodes, max_results, embedding_coverage=0.0): + """ + Combine and deduplicate search results from vector and fuzzy text search with adaptive scoring. + + Args: + vector_nodes (list): Results from vector search + fuzzy_nodes (list): Results from fuzzy text search + max_results (int): Maximum number of results to return + embedding_coverage (float): Percentage of nodes that have embeddings (0.0 to 1.0) + + Returns: + list: Combined and deduplicated results + """ + combined = {} + + # Add vector search results + for node in vector_nodes: + element_id = node["element_id"] + if element_id not in combined: + combined[element_id] = node + combined[element_id]["search_method"] = "hybrid_vector_fuzzy" + combined[element_id]["primary_method"] = "vector" + + # Add fuzzy text search results + for node in fuzzy_nodes: + element_id = node["element_id"] + if element_id not in combined: + combined[element_id] = node + combined[element_id]["search_method"] = "hybrid_vector_fuzzy" + combined[element_id]["primary_method"] = "fuzzy_text" + else: + # If already exists from vector search, add fuzzy match info + existing = combined[element_id] + if "fuzzy_match_ratio" not in existing: + existing["fuzzy_match_ratio"] = node.get("match_ratio", 0) + + # Adaptive scoring based on embedding coverage + sorted_results = [] + for node in combined.values(): + vector_score = node.get("similarity_score", 0) + fuzzy_score = node.get("match_ratio", 0) + + # Adaptive weights based on embedding coverage + if embedding_coverage < 0.1: # Less than 10% coverage + # Heavily favor fuzzy text when embeddings are scarce + vector_weight = 0.1 + fuzzy_weight = 0.9 + logging.info(f"Low embedding coverage ({embedding_coverage:.1%}), favoring fuzzy text") + elif embedding_coverage < 0.5: # Less than 50% coverage + # Balance towards fuzzy text + vector_weight = 0.3 + fuzzy_weight = 0.7 + logging.info(f"Medium embedding coverage ({embedding_coverage:.1%}), balanced approach") + else: # 50%+ coverage + # Favor vector search when embeddings are abundant + vector_weight = 0.7 + fuzzy_weight = 0.3 + logging.info(f"High embedding coverage ({embedding_coverage:.1%}), favoring vector search") + + # Calculate combined score with adaptive weights + combined_score = (vector_score * vector_weight) + (fuzzy_score * fuzzy_weight) + node["combined_score"] = round(combined_score, 4) + node["vector_weight"] = vector_weight + node["fuzzy_weight"] = fuzzy_weight + + sorted_results.append(node) + + # Sort by combined score descending + sorted_results.sort(key=lambda x: x["combined_score"], reverse=True) + + return sorted_results[:max_results] + + +def get_subgraph_from_node(uri, username, password, database, node_id, depth=4, max_nodes=1000, preserve_text=False): + """ + Extracts a subgraph starting from a specific node with configurable depth. + + Args: + uri (str): The URI for the Neo4j database. + username (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + node_id (str): The element ID of the starting node. + depth (int): The maximum depth of the subgraph (default: 4). + max_nodes (int): Maximum number of nodes to include in the subgraph. + + Returns: + dict: Contains the subgraph nodes and relationships. + """ + try: + logging.info(f"Extracting subgraph from node {node_id} with depth {depth}") + driver = get_graphDB_driver(uri, username, password, database) + + # Subgraph extraction query - using string formatting for depth since Neo4j doesn't allow parameters in MATCH patterns + subgraph_query = f""" + MATCH (startNode) + WHERE elementId(startNode) = $node_id + MATCH path = (startNode)-[*1..{depth}]-(connectedNode) + WITH startNode, collect(DISTINCT path) AS paths + UNWIND paths AS path + WITH startNode, path, nodes(path) AS pathNodes, relationships(path) AS pathRels + UNWIND pathNodes AS node + WITH startNode, path, pathRels, collect(DISTINCT node) AS allNodes + UNWIND pathRels AS rel + WITH startNode, allNodes, collect(DISTINCT rel) AS allRels + + // Also include Document nodes for chunks to get source URLs + WITH startNode, allNodes, allRels + OPTIONAL MATCH (c:Chunk)-[:PART_OF]->(d:Document) + WHERE c IN allNodes + WITH startNode, allNodes, collect(d) AS docNodes, allRels + WITH startNode, allNodes + docNodes AS allNodes, allRels + RETURN allNodes AS nodes, allRels AS relationships + LIMIT $max_nodes + """ + + records, summary, keys = driver.execute_query( + subgraph_query, + node_id=node_id, + max_nodes=max_nodes + ) + + if not records: + logging.warning(f"No subgraph found for node {node_id}") + return {"nodes": [], "relationships": []} + + # Process nodes and relationships + all_nodes = set() + all_relationships = set() + + for record in records: + # Process nodes + for node in record["nodes"]: + node_element = process_node(node, preserve_text=preserve_text) + all_nodes.add(json.dumps(node_element, sort_keys=True)) + + # Process relationships + for rel in record["relationships"]: + rel_element = { + "element_id": rel.element_id, + "type": rel.type, + "start_node_id": rel.start_node.element_id, + "end_node_id": rel.end_node.element_id, + "properties": {} + } + + for key in rel: + if key in ["embedding", "text", "summary"]: + continue + value = rel.get(key) + if isinstance(value, time.DateTime): + rel_element["properties"][key] = value.isoformat() + else: + rel_element["properties"][key] = value + + all_relationships.add(json.dumps(rel_element, sort_keys=True)) + + # Convert back to dictionaries + nodes = [json.loads(node_str) for node_str in all_nodes] + relationships = [json.loads(rel_str) for rel_str in all_relationships] + + logging.info(f"Extracted subgraph with {len(nodes)} nodes and {len(relationships)} relationships") + return { + "start_node_id": node_id, + "depth": depth, + "nodes": nodes, + "relationships": relationships + } + + except Exception as e: + logging.error(f"An error occurred in get_subgraph_from_node. Error: {str(e)}") + raise Exception(f"An error occurred in get_subgraph_from_node. Please check the logs for more details.") from e + finally: + if driver: + driver.close() + + +def search_and_get_subgraph(uri, username, password, database, search_term, node_type="Person", depth=4, max_results=10, extract_best_match_only=True, preserve_text=False): + """ + Combines search and subgraph extraction in one operation. + + Args: + uri (str): The URI for the Neo4j database. + username (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + search_term (str): The search term to look for. + node_type (str): The type of node to search for (default: "Person"). + depth (int): The maximum depth of the subgraph (default: 4). + max_results (int): Maximum number of search results to process. + extract_best_match_only (bool): Whether to extract subgraph only for the best match (default: True). + + Returns: + dict: Contains search results and their subgraphs. + """ + try: + logging.info(f"Searching for '{search_term}' and extracting subgraphs") + + # First, search for matching nodes + search_results = search_nodes(uri, username, password, database, search_term, node_type, max_results) + + if not search_results["nodes"]: + return { + "search_term": search_term, + "node_type": node_type, + "total_results": 0, + "subgraphs": [], + "best_match": None + } + + # Log all matching nodes with their scores + logging.info(f"Found {len(search_results['nodes'])} matching nodes:") + for i, node in enumerate(search_results["nodes"][:5]): # Log top 5 matches + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + similarity_score = node.get('similarity_score', 'N/A') + match_ratio = node.get('match_ratio', 'N/A') + search_method = node.get('search_method', 'unknown') + + logging.info(f" {i+1}. {node_name}") + logging.info(f" Combined Score: {combined_score}") + logging.info(f" Vector Similarity: {similarity_score}") + logging.info(f" Fuzzy Match Ratio: {match_ratio}") + logging.info(f" Search Method: {search_method}") + + # Determine the best match + best_match = search_results["nodes"][0] # First result is the best match + best_match_name = best_match.get('properties', {}).get('id', 'Unknown') + best_match_score = best_match.get('combined_score', best_match.get('similarity_score', best_match.get('match_ratio', 'N/A'))) + + logging.info(f"Selected best match: '{best_match_name}' with score: {best_match_score}") + + # Extract subgraphs based on configuration + subgraphs = [] + nodes_to_extract = [best_match] if extract_best_match_only else search_results["nodes"][:max_results] + + for node in nodes_to_extract: + try: + logging.info(f"Extracting subgraph from node: {node.get('properties', {}).get('id', 'Unknown')}") + subgraph = get_subgraph_from_node( + uri, username, password, database, + node["element_id"], depth, preserve_text=preserve_text + ) + subgraph["matching_node"] = node + subgraphs.append(subgraph) + + if extract_best_match_only: + logging.info(f"Extracted subgraph with {len(subgraph.get('nodes', []))} nodes and {len(subgraph.get('relationships', []))} relationships") + break # Only extract from best match + + except Exception as e: + logging.warning(f"Failed to extract subgraph for node {node['element_id']}: {str(e)}") + continue + + return { + "search_term": search_term, + "node_type": node_type, + "total_results": len(search_results["nodes"]), + "subgraphs": subgraphs, + "best_match": { + "node_name": best_match_name, + "score": best_match_score, + "search_method": best_match.get('search_method', 'unknown'), + "element_id": best_match.get('element_id') + }, + "all_matches": [ + { + "node_name": node.get('properties', {}).get('id', 'Unknown'), + "score": node.get('combined_score', node.get('similarity_score', node.get('match_ratio', 'N/A'))), + "search_method": node.get('search_method', 'unknown'), + "element_id": node.get('element_id') + } + for node in search_results["nodes"][:5] # Top 5 matches + ] + } + + except Exception as e: + logging.error(f"An error occurred in search_and_get_subgraph. Error: {str(e)}") + raise Exception(f"An error occurred in search_and_get_subgraph. Please check the logs for more details.") from e + + +def diagnose_database_entities(uri, username, password, database): + """ + Diagnostic function to check what entities exist in the database. + + Args: + uri (str): The URI for the Neo4j database. + username (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + + Returns: + dict: Contains diagnostic information about entities in the database. + """ + try: + logging.info("Starting database entity diagnosis...") + driver = get_graphDB_driver(uri, username, password, database) + + # Query to get all entity types and their counts based on labels + entity_types_query = """ + MATCH (n:__Entity__) + UNWIND labels(n) AS label + WITH label + WHERE label <> '__Entity__' + RETURN label as entity_type, count(*) as count + ORDER BY count DESC + """ + + # Query to get sample entities with their actual structure + sample_entities_query = """ + MATCH (n:__Entity__) + RETURN labels(n) as labels, n.id as id, n.name as name, n.description as description, n.type as type + LIMIT 10 + """ + + # Query to get all labels in the database + labels_query = """ + CALL db.labels() YIELD label + RETURN collect(label) as labels + """ + + logging.info("Executing diagnostic queries...") + + # Get entity types and counts + entity_types_result = driver.execute_query(entity_types_query) + entity_types = [{"type": record["entity_type"], "count": record["count"]} for record in entity_types_result[0]] + + # Get sample entities + sample_entities_result = driver.execute_query(sample_entities_query) + sample_entities = [{"labels": record["labels"], "id": record["id"], "name": record["name"], "description": record["description"], "type": record["type"]} for record in sample_entities_result[0]] + + # Get all labels + labels_result = driver.execute_query(labels_query) + all_labels = labels_result[0][0]["labels"] if labels_result[0] else [] + + logging.info(f"Diagnosis completed. Found {len(entity_types)} entity types") + + return { + "entity_types": entity_types, + "sample_entities": sample_entities, + "all_labels": all_labels, + "total_entity_types": len(entity_types), + "total_sample_entities": len(sample_entities) + } + + except Exception as e: + logging.error(f"An error occurred in diagnose_database_entities. Error: {str(e)}") + raise Exception(f"An error occurred in diagnose_database_entities. Please check the logs for more details.") from e + finally: + if driver: + driver.close() diff --git a/backend/src/main.py b/backend/src/main.py index 4bdb6ba51..e37f7a082 100644 --- a/backend/src/main.py +++ b/backend/src/main.py @@ -23,7 +23,7 @@ from src.shared.common_fn import * from src.make_relationships import * from src.document_sources.web_pages import * -from src.graph_query import get_graphDB_driver +from src.graph_query import get_graphDB_driver, search_nodes, get_subgraph_from_node, search_and_get_subgraph, diagnose_database_entities import re from langchain_community.document_loaders import WikipediaLoader, WebBaseLoader import warnings @@ -765,4 +765,143 @@ def failed_file_process(uri,file_name, merged_file_path): delete_file_from_gcs(BUCKET_UPLOAD,folder_name,file_name) else: logging.info(f'Deleted File Path: {merged_file_path} and Deleted File Name : {file_name}') - delete_uploaded_local_file(merged_file_path,file_name) \ No newline at end of file + delete_uploaded_local_file(merged_file_path,file_name) + +def search_nodes_api(uri, userName, password, database, search_term, node_type="Person", max_results=50, prefer_vector=True, use_hybrid=True): + """ + API endpoint for searching nodes across all documents with hybrid vector and fuzzy text search support. + + Args: + uri (str): The URI for the Neo4j database. + userName (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + search_term (str): The search term to look for. + node_type (str): The type of node to search for (default: "Person"). + max_results (int): Maximum number of results to return. + prefer_vector (bool): Whether to prefer vector search over text search when available. + use_hybrid (bool): Whether to use hybrid search combining vector and fuzzy text. + + Returns: + dict: Contains matching nodes with their properties and search method info. + """ + try: + logging.info(f"API: Searching for nodes with term '{search_term}' in type '{node_type}' (prefer_vector={prefer_vector}, hybrid={use_hybrid})") + result = search_nodes(uri, userName, password, database, search_term, node_type, max_results, prefer_vector, use_hybrid) + return result + except Exception as e: + logging.error(f"API: Error in search_nodes_api: {str(e)}") + raise Exception(f"Failed to search nodes: {str(e)}") + + +def get_subgraph_api(uri, userName, password, database, node_id, depth=4, max_nodes=1000): + """ + API endpoint for extracting subgraph from a specific node. + + Args: + uri (str): The URI for the Neo4j database. + userName (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + node_id (str): The element ID of the starting node. + depth (int): The maximum depth of the subgraph (default: 4). + max_nodes (int): Maximum number of nodes to include in the subgraph. + + Returns: + dict: Contains the subgraph nodes and relationships. + """ + try: + logging.info(f"API: Extracting subgraph from node {node_id} with depth {depth}") + result = get_subgraph_from_node(uri, userName, password, database, node_id, depth, max_nodes) + return result + except Exception as e: + logging.error(f"API: Error in get_subgraph_api: {str(e)}") + raise Exception(f"Failed to extract subgraph: {str(e)}") + + +def search_and_get_subgraph_api(uri, userName, password, database, search_term, node_type="Person", depth=4, max_results=10, extract_best_match_only=True): + """ + API endpoint for combined search and subgraph extraction. + + Args: + uri (str): The URI for the Neo4j database. + userName (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + search_term (str): The search term to look for. + node_type (str): The type of node to search for (default: "Person"). + depth (int): The maximum depth of the subgraph (default: 4). + max_results (int): Maximum number of search results to process. + extract_best_match_only (bool): Whether to extract subgraph only for the best match (default: True). + + Returns: + dict: Contains search results and their subgraphs. + """ + try: + logging.info(f"API: Searching and extracting subgraphs for term '{search_term}' (extract_best_match_only={extract_best_match_only})") + result = search_and_get_subgraph(uri, userName, password, database, search_term, node_type, depth, max_results, extract_best_match_only) + return result + except Exception as e: + logging.error(f"API: Error in search_and_get_subgraph_api: {str(e)}") + raise Exception(f"Failed to search and extract subgraph: {str(e)}") + +def diagnose_database_entities_api(uri, userName, password, database): + """ + API endpoint for diagnosing database entities. + + Args: + uri (str): The URI for the Neo4j database. + userName (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + + Returns: + dict: Contains diagnostic information about entities in the database. + """ + try: + logging.info(f"API: Diagnosing database entities") + result = diagnose_database_entities(uri, userName, password, database) + return result + except Exception as e: + logging.error(f"API: Error in diagnose_database_entities_api: {str(e)}") + raise Exception(f"Failed to diagnose database entities: {str(e)}") + +def analyze_risk_api(uri, userName, password, database, entity_name, entity_type, risk_indicators, depth=4, max_results=10): + """ + API endpoint for analyzing research security risk of an entity. + + Args: + uri (str): The URI for the Neo4j database. + userName (str): The username for authentication. + password (str): The password for authentication. + database (str): The database name. + entity_name (str): Name of the entity to assess. + entity_type (str): Type of entity (individual or organization). + risk_indicators (dict): Dictionary of risk indicators and their weights. + depth (int): Depth for subgraph extraction (default: 4). + max_results (int): Maximum number of search results to consider (default: 10). + + Returns: + dict: Complete risk assessment result. + """ + try: + logging.info(f"API: Analyzing risk for entity '{entity_name}' ({entity_type})") + + # Import here to avoid circular imports + from src.risk_assessment import analyze_risk + + result = analyze_risk( + uri=uri, + username=userName, + password=password, + database=database, + entity_name=entity_name, + entity_type=entity_type, + risk_indicators=risk_indicators, + depth=depth, + max_results=max_results + ) + return result + except Exception as e: + logging.error(f"API: Error in analyze_risk_api: {str(e)}") + raise Exception(f"Failed to analyze risk: {str(e)}") \ No newline at end of file diff --git a/backend/src/make_relationships.py b/backend/src/make_relationships.py index 97aa7e33e..8c2451191 100644 --- a/backend/src/make_relationships.py +++ b/backend/src/make_relationships.py @@ -66,6 +66,27 @@ def create_chunk_embeddings(graph, chunkId_chunkDoc_list, file_name): def create_relation_between_chunks(graph, file_name, chunks: List[Document])->list: logging.info("creating FIRST_CHUNK and NEXT_CHUNK relationships between chunks") + + # Get document URL and source information first + doc_url = None + file_source = None + try: + doc_url_query = "MATCH (d:Document {fileName: $f_name}) RETURN d.url as url, d.fileSource as source" + doc_result = execute_graph_query(graph, doc_url_query, {"f_name": file_name}) + if doc_result: + doc_url = doc_result[0]['url'] + file_source = doc_result[0]['source'] + logging.info(f"Found document URL: {doc_url}, source: {file_source}") + else: + logging.warning(f"No document found for file: {file_name}") + except Exception as e: + logging.warning(f"Error getting document URL for {file_name}: {str(e)}") + + # Create local file reference if no URL exists + if not doc_url and file_source == 'local file': + doc_url = f"local://{file_name}" + logging.info(f"Created local file reference: {doc_url}") + current_chunk_id = "" lst_chunks_including_hash = [] batch_data = [] @@ -93,6 +114,8 @@ def create_relation_between_chunks(graph, file_name, chunks: List[Document])->li "position": position, "length": chunk_document.metadata["length"], "f_name": file_name, + "url": doc_url, # Add URL to chunk data + "fileSource": file_source, # Add file source to chunk data "previous_id" : previous_chunk_id, "content_offset" : offset } @@ -121,7 +144,7 @@ def create_relation_between_chunks(graph, file_name, chunks: List[Document])->li query_to_create_chunk_and_PART_OF_relation = """ UNWIND $batch_data AS data MERGE (c:Chunk {id: data.id}) - SET c.text = data.pg_content, c.position = data.position, c.length = data.length, c.fileName=data.f_name, c.content_offset=data.content_offset + SET c.text = data.pg_content, c.position = data.position, c.length = data.length, c.fileName=data.f_name, c.url=data.url, c.fileSource=data.fileSource, c.content_offset=data.content_offset WITH data, c SET c.page_number = CASE WHEN data.page_number IS NOT NULL THEN data.page_number END, c.start_time = CASE WHEN data.start_time IS NOT NULL THEN data.start_time END, diff --git a/backend/src/mcp_config.py b/backend/src/mcp_config.py new file mode 100644 index 000000000..8aa314193 --- /dev/null +++ b/backend/src/mcp_config.py @@ -0,0 +1,79 @@ +""" +MCP Server Configuration +Automatic configuration based on environment variables +""" + +import os +from typing import Dict, Any + +class MCPConfig: + """Configuration manager for MCP Neo4j server""" + + def __init__(self): + """Initialize MCP configuration based on environment variables""" + self.server_url = self._get_server_url() + self.use_local_process = self._should_use_local() + self.timeout = 30.0 + + def _get_server_url(self) -> str: + """Get server URL from environment or default to remote""" + # Check if remote server URL is provided + remote_url = os.getenv("MCP_SERVER_URL") + if remote_url: + # Ensure remote URL has /mcp/ path + if not remote_url.endswith("/mcp/"): + if not remote_url.endswith("/"): + remote_url += "/" + if not remote_url.endswith("mcp/"): + remote_url += "mcp/" + return remote_url + + # Default to local server if no remote URL provided + return "http://localhost:8001/api/mcp/" + + def _should_use_local(self) -> bool: + """Check if should use local server (no remote URL provided)""" + return not bool(os.getenv("MCP_SERVER_URL")) + + def get_local_server_args(self, neo4j_config: Dict[str, str]) -> list: + """Get command line arguments for starting local MCP server""" + if not self.use_local_process: + raise ValueError("Cannot get local server args when using remote server") + + return [ + "mcp-neo4j-cypher", + "--transport", "http", + "--server-host", "127.0.0.1", + "--server-port", "8001", + "--server-path", "/api/mcp/", + "--db-url", neo4j_config["uri"], + "--username", neo4j_config["username"], + "--password", neo4j_config["password"], + "--database", neo4j_config["database"] + ] + + def get_description(self) -> str: + """Get human-readable description of current configuration""" + if self.use_local_process: + return "Local MCP Neo4j server" + else: + return f"Remote MCP Neo4j server at {self.server_url}" + +# Global configuration instance +mcp_config = MCPConfig() + +def get_mcp_config() -> MCPConfig: + """Get the global MCP configuration instance""" + return mcp_config + +def get_server_url() -> str: + """Get current server URL""" + return mcp_config.server_url + +def should_start_local_process() -> bool: + """Check if should start local process""" + return mcp_config.use_local_process + +def get_timeout() -> float: + """Get current timeout setting""" + return mcp_config.timeout diff --git a/backend/src/mcp_service.py b/backend/src/mcp_service.py new file mode 100644 index 000000000..6819d51ae --- /dev/null +++ b/backend/src/mcp_service.py @@ -0,0 +1,800 @@ +""" +MCP Neo4j Service for NRC MVP +Provides natural language query processing and chart generation using MCP Neo4j server +""" + +import asyncio +import json +import logging +import subprocess +import httpx +from typing import Dict, Any, List, Optional +import openai +from datetime import datetime +from src.constants.chart_prompts import create_cypher_query_prompt, create_chart_formatting_prompt +from src.mcp_config import get_mcp_config, get_server_url, should_start_local_process, get_timeout + +logger = logging.getLogger(__name__) + +class MCPNeo4jService: + """Service for MCP Neo4j integration""" + + def __init__(self): + """Initialize the MCP service""" + self.mcp_process = None + self.http_client = None + self.config = get_mcp_config() + self.server_url = get_server_url() + self.openai_client = None + logger.info(f"MCP Service initialized: {self.config.get_description()}") + + async def _init_http_client(self): + """Initialize HTTP client""" + if not self.http_client: + self.http_client = httpx.AsyncClient(timeout=get_timeout()) + logger.info("HTTP client initialized") + + async def start_mcp_server(self, neo4j_config: Dict[str, str]) -> bool: + """Start the MCP Neo4j server as a subprocess (only for local mode)""" + if not should_start_local_process(): + logger.info("Using remote MCP server, skipping local process start") + # Initialize HTTP client for remote server + self.http_client = httpx.AsyncClient(timeout=get_timeout()) + logger.info("HTTP client initialized for remote MCP server") + return True + + try: + # Get command line arguments from config + cmd = self.config.get_local_server_args(neo4j_config) + + logger.info(f"Starting MCP server with command: {' '.join(cmd)}") + + self.mcp_process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + + # Wait for server to start + await asyncio.sleep(3) + + # Check if process is still running + if self.mcp_process.poll() is not None: + stdout, stderr = self.mcp_process.communicate() + logger.error(f"MCP server process exited early. stdout: {stdout.decode()}, stderr: {stderr.decode()}") + return False + + # Initialize HTTP client + self.http_client = httpx.AsyncClient(timeout=get_timeout()) + + logger.info("MCP Neo4j server started successfully") + return True + + except Exception as e: + logger.error(f"Failed to start MCP server: {e}") + return False + + async def stop_mcp_server(self): + """Stop the MCP server process""" + if self.mcp_process: + self.mcp_process.terminate() + self.mcp_process.wait() + logger.info("MCP Neo4j server stopped") + + if self.http_client: + await self.http_client.aclose() + + def _parse_sse_response(self, sse_text: str) -> Optional[Dict[str, Any]]: + """Parse Server-Sent Events response format""" + try: + logger.info(f"SSE text to parse: {sse_text[:200]}...") + + lines = sse_text.strip().split('\n') + data_line = None + + for line in lines: + if line.startswith('data: '): + data_line = line[6:] # Remove 'data: ' prefix + break + + if data_line: + logger.info(f"Found data line: {data_line[:200]}...") + return json.loads(data_line) + else: + logger.error("No data line found in SSE response") + # Try to parse the entire response as JSON + try: + return json.loads(sse_text) + except: + return None + + except Exception as e: + logger.error(f"Error parsing SSE response: {e}") + return None + + async def execute_cypher_query(self, query: str) -> Dict[str, Any]: + """Execute a Cypher query via MCP""" + try: + if not self.http_client: + raise Exception("HTTP client not initialized") + + # Use different tool names for local vs remote servers + tool_name = "read_neo4j_cypher" if self.config.use_local_process else "neo4j-mcp-read_neo4j_cypher" + + mcp_request = { + "jsonrpc": "2.0", + "id": 1, + "method": "tools/call", + "params": { + "name": tool_name, + "arguments": { + "query": query + } + } + } + + response = await self.http_client.post( + self.server_url, + json=mcp_request, + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream" + }, + timeout=get_timeout() + ) + + if response.status_code == 200: + logger.info(f"Raw MCP response: {response.text[:500]}...") + result = self._parse_sse_response(response.text) + logger.info(f"Parsed SSE result: {result}") + + if result and "result" in result: + result_content = result["result"]["content"][0] + result_data = result_content["text"] + logger.info(f"Result data: {result_data[:200]}...") + + # Check if this is an error response + if result_content.get("isError", False) or "Error:" in result_data or "Neo4j Error:" in result_data: + logger.error(f"Cypher query error: {result_data}") + return { + "success": False, + "error": f"Cypher query failed: {result_data}", + "query": query + } + + try: + parsed_data = json.loads(result_data) + return { + "success": True, + "data": parsed_data, + "query": query + } + except json.JSONDecodeError: + # If it's not JSON, treat as raw text data + return { + "success": True, + "data": [{"value": result_data, "type": "text"}], + "query": query + } + elif result and "error" in result: + return { + "success": False, + "error": result["error"], + "query": query + } + else: + logger.error(f"No valid result in MCP response: {result}") + return { + "success": False, + "error": "No valid result in MCP response", + "query": query + } + + return { + "success": False, + "error": f"HTTP request failed: {response.text}", + "query": query + } + + except Exception as e: + error_msg = str(e) + if "timeout" in error_msg.lower(): + logger.error(f"Cypher query timed out: {e}") + error_msg = "Query execution timed out. Please try a simpler query." + elif "connection" in error_msg.lower(): + logger.error(f"MCP server connection failed: {e}") + error_msg = "MCP server connection failed. Please check if the server is running." + else: + logger.error(f"Failed to execute Cypher query: {e}") + + return { + "success": False, + "error": error_msg, + "query": query + } + + async def get_database_schema(self) -> Dict[str, Any]: + """Get database schema information via MCP""" + try: + if not self.http_client: + return {"success": False, "error": "HTTP client not initialized"} + + # Use different tool names for local vs remote servers + tool_name = "get_neo4j_schema" if self.config.use_local_process else "neo4j-mcp-get_neo4j_schema" + + mcp_request = { + "jsonrpc": "2.0", + "id": 2, + "method": "tools/call", + "params": { + "name": tool_name, + "arguments": {} + } + } + + response = await self.http_client.post( + self.server_url, + json=mcp_request, + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream" + } + ) + + if response.status_code == 200: + result = self._parse_sse_response(response.text) + if result and "result" in result: + schema = result["result"]["content"][0]["text"] + return { + "success": True, + "schema": json.loads(schema) + } + + return { + "success": False, + "error": f"Failed to get schema: {response.text}" + } + + except Exception as e: + logger.error(f"Failed to get database schema: {e}") + return { + "success": False, + "error": str(e) + } + + def _create_query_prompt(self, query: str, schema: Dict[str, Any]) -> str: + """Create a prompt for OpenAI to generate Cypher queries""" + schema_info = None + if schema and schema.get("success"): + schema_data = schema["schema"] + schema_info = { + 'labels': list(schema_data.keys()) if isinstance(schema_data, dict) else [], + 'relationship_types': [], + 'property_keys': [] + } + + return create_cypher_query_prompt(query, schema_info) + + async def process_natural_language_query(self, query: str, openai_api_key: str = None, model: str = "gpt-4") -> Dict[str, Any]: + """Process natural language query and generate SVG chart""" + try: + if not self.http_client: + raise Exception("HTTP client not initialized") + + # Initialize OpenAI client if not already done + if not self.openai_client: + self.openai_client = openai.OpenAI(api_key=openai_api_key) + + # Get database schema for context + schema = await self.get_database_schema() + + # Create prompt for OpenAI + prompt = self._create_query_prompt(query, schema) + + # Call OpenAI to generate Cypher query + response = self.openai_client.chat.completions.create( + model=model, + messages=[ + { + "role": "system", + "content": "You are a Neo4j Cypher query expert. Generate accurate Cypher queries based on the database schema and user questions." + }, + { + "role": "user", + "content": prompt + } + ], + temperature=0.1, + max_tokens=1000 + ) + + # Extract Cypher query from response + cypher_query = response.choices[0].message.content.strip() + + # Clean up the query (remove markdown formatting if present) + if cypher_query.startswith("```cypher"): + cypher_query = cypher_query[9:] + if cypher_query.startswith("```"): + cypher_query = cypher_query[3:] + if cypher_query.endswith("```"): + cypher_query = cypher_query[:-3] + + cypher_query = cypher_query.strip() + + logger.info(f"Generated Cypher query: {cypher_query}") + + # Execute the query via MCP + query_result = await self.execute_cypher_query(cypher_query) + + if query_result["success"]: + # Check if we got actual data or an error message + data = query_result["data"] + if isinstance(data, list) and len(data) > 0 and not any("Error" in str(item) for item in data): + # Generate complete React component using LLM + logger.info(f"Query successful, generating React component for {len(data)} data points") + chart_artifact = self._generate_react_component(query, data, openai_api_key, model) + logger.info(f"Chart artifact result: {chart_artifact}") + + # Check if LLM generation was successful + if chart_artifact and not chart_artifact.get("error"): + return { + "success": True, + "natural_language_query": query, + "cypher_query": cypher_query, + "chartData": chart_artifact.get("chartData"), + "chartConfig": chart_artifact.get("chartConfig"), + "chartType": chart_artifact.get("chartType"), + "raw_data": data + } + else: + # LLM failed, try fallback chart generation + logger.warning(f"LLM chart generation failed: {chart_artifact.get('error', 'Unknown error')}. Using fallback chart generation...") + fallback_chart = self._create_fallback_chart_data(query, data) + return { + "success": True, + "natural_language_query": query, + "cypher_query": cypher_query, + "chartData": fallback_chart.get("chartData"), + "chartConfig": fallback_chart.get("chartConfig"), + "chartType": fallback_chart.get("chartType"), + "raw_data": data + } + else: + # Query returned errors, try simpler fallback query + logger.warning(f"Query returned error data: {data}. Trying simpler fallback query...") + fallback_query = "MATCH (n) RETURN labels(n)[0] as name, count(*) as count LIMIT 10" + fallback_result = await self.execute_cypher_query(fallback_query) + + if fallback_result["success"]: + # Try LLM generation first with fallback data + chart_artifact = self._generate_react_component(query, fallback_result["data"], openai_api_key, model) + if chart_artifact and not chart_artifact.get("error"): + return { + "success": True, + "natural_language_query": query, + "cypher_query": f"{cypher_query} (fallback: {fallback_query})", + "chartData": chart_artifact.get("chartData"), + "chartConfig": chart_artifact.get("chartConfig"), + "chartType": chart_artifact.get("chartType"), + "raw_data": fallback_result["data"] + } + else: + # Use fallback chart generation + fallback_chart = self._create_fallback_chart_data(query, fallback_result["data"]) + return { + "success": True, + "natural_language_query": query, + "cypher_query": f"{cypher_query} (fallback: {fallback_query})", + "chartData": fallback_chart.get("chartData"), + "chartConfig": fallback_chart.get("chartConfig"), + "chartType": fallback_chart.get("chartType"), + "raw_data": fallback_result["data"] + } + else: + return { + "success": False, + "natural_language_query": query, + "cypher_query": cypher_query, + "error": f"Query failed: {query_result.get('error', 'Unknown error')}" + } + else: + # Try a fallback simple query if the complex one failed + logger.warning(f"Complex query failed: {query_result['error']}. Trying fallback query...") + fallback_query = "MATCH (n) RETURN labels(n)[0] as name, count(*) as count LIMIT 10" + fallback_result = await self.execute_cypher_query(fallback_query) + + if fallback_result["success"]: + chart_artifact = self._generate_react_component(query, fallback_result["data"], openai_api_key, model) + return { + "success": True, + "natural_language_query": query, + "cypher_query": f"{cypher_query} (fallback: {fallback_query})", + "chartData": chart_artifact.get("chartData"), + "chartConfig": chart_artifact.get("chartConfig"), + "chartType": chart_artifact.get("chartType"), + "raw_data": fallback_result["data"] + } + else: + return { + "success": False, + "natural_language_query": query, + "cypher_query": cypher_query, + "error": f"Original query failed: {query_result['error']}. Fallback also failed: {fallback_result['error']}" + } + + except Exception as e: + logger.error(f"Failed to process natural language query: {e}") + return { + "success": False, + "natural_language_query": query, + "error": str(e) + } + + def _generate_react_component(self, query: str, raw_data: List[Dict], openai_api_key: str, model: str) -> Dict[str, Any]: + """Generate structured chart data and config using LLM""" + try: + if not raw_data: + return {"error": "No data available"} + + # Use all the data - don't limit it + logger.info(f"Using all data: {len(raw_data)} items") + + # Create prompt for LLM to generate structured data + prompt = create_chart_formatting_prompt(query, raw_data) + + # Initialize OpenAI client if not already done + if not self.openai_client: + self.openai_client = openai.OpenAI(api_key=openai_api_key) + + # Call OpenAI to generate structured chart data with retry logic + max_retries = 2 + for attempt in range(max_retries): + try: + response = self.openai_client.chat.completions.create( + model=model, + messages=[ + { + "role": "system", + "content": "You are a data visualization expert. Generate structured chart data and configuration in JSON format." + }, + { + "role": "user", + "content": prompt + } + ], + temperature=0.1, + max_tokens=1500 + ) + break # Success, exit retry loop + except Exception as e: + if attempt == max_retries - 1: + logger.error(f"OpenAI API call failed after {max_retries} attempts: {e}") + return {"error": f"OpenAI API call failed: {str(e)}"} + else: + logger.warning(f"OpenAI API call attempt {attempt + 1} failed: {e}. Retrying...") + continue + + # Extract the JSON response + json_content = response.choices[0].message.content.strip() + + logger.info(f"Raw LLM response length: {len(json_content)}") + logger.info(f"Raw LLM response first 200 chars: {json_content[:200]}") + + # Clean up the response (remove any markdown formatting) + if json_content.startswith("```json"): + json_content = json_content[7:] + elif json_content.startswith("```"): + json_content = json_content[3:] + if json_content.endswith("```"): + json_content = json_content[:-3] + + json_content = json_content.strip() + + logger.info(f"Cleaned LLM response length: {len(json_content)}") + logger.info(f"Cleaned LLM response first 200 chars: {json_content[:200]}") + + # Parse the JSON response + try: + chart_data = json.loads(json_content) + logger.info("โœ… Successfully parsed JSON response") + + # Validate the structure + if "chartData" not in chart_data or "chartConfig" not in chart_data: + raise ValueError("Missing required fields: chartData or chartConfig") + + # Debug: Check for list values in chartData + for i, item in enumerate(chart_data["chartData"]): + if not isinstance(item, dict): + logger.warning(f"chartData item {i} is not a dict: {item}") + continue + for key, value in item.items(): + if isinstance(value, list): + logger.warning(f"chartData item {i} has list value for key '{key}': {value}") + + # Validate and ensure data format matches frontend expectations + validated_data = self._validate_chart_data(chart_data["chartData"], chart_data.get("type", "bar")) + + return { + "chartData": validated_data, + "chartConfig": chart_data["chartConfig"], + "chartType": chart_data.get("type", "bar") + } + + except json.JSONDecodeError as e: + logger.error(f"Failed to parse JSON response: {e}") + logger.error(f"Response content: {json_content}") + + # Fallback: create simple structured data + return self._create_fallback_chart_data(query, raw_data) + + except Exception as e: + logger.error(f"Error generating chart data: {e}") + return {"error": f"Failed to generate chart: {str(e)}"} + + def _create_fallback_chart_data(self, query: str, raw_data: List[Dict]) -> Dict[str, Any]: + """Create simple fallback chart data when LLM fails""" + try: + logger.info(f"Creating fallback chart data for query: {query}") + + # Determine chart type from query + chart_type = self._infer_chart_type_from_query(query) + + if not raw_data: + return { + "chartData": [{"name": "No Data", "value": 0}], + "chartConfig": {"No Data": {"label": "No Data", "color": "#94a3b8"}}, + "chartType": chart_type + } + + # Process raw data into simple format + chart_data = [] + chart_config = {} + colors = ["#2563eb", "#60a5fa", "#93c5fd", "#dbeafe", "#1e40af", "#1d4ed8"] + + for i, item in enumerate(raw_data[:20]): # Increased limit for more data + # Try multiple possible name fields + name = (item.get("name") or item.get("NodeType") or item.get("RelationshipType") or + item.get("Category") or item.get("SourceType") or item.get("TargetType") or + item.get("Date") or item.get("Type") or f"Item {i+1}") + + # Try multiple possible value fields + value = (item.get("count") or item.get("Count") or item.get("value") or + item.get("Value") or item.get("Total") or item.get("Amount") or 0) + + # Ensure name is a string, not a list + if isinstance(name, list): + name = str(name[0]) if name else f"Item {i+1}" + elif not isinstance(name, str): + name = str(name) if name else f"Item {i+1}" + + # Ensure value is a number + if not isinstance(value, (int, float)): + try: + value = float(value) if value else 0 + except (ValueError, TypeError): + value = 0 + + # Ensure data format matches frontend expectations + chart_data.append({"name": name, "value": value}) + chart_config[name] = { + "label": name, + "color": colors[i % len(colors)] + } + + # Validate the generated data + validated_data = self._validate_chart_data(chart_data, chart_type) + + return { + "chartData": validated_data, + "chartConfig": chart_config, + "chartType": chart_type + } + + except Exception as e: + logger.error(f"Error creating fallback chart data: {e}") + logger.error(f"Raw data that caused error: {raw_data}") + import traceback + logger.error(f"Traceback: {traceback.format_exc()}") + return { + "chartData": [{"name": "Error", "value": 0}], + "chartConfig": {"Error": {"label": "Error", "color": "#ef4444"}}, + "chartType": self._infer_chart_type_from_query(query) + } + + def _validate_chart_data(self, data: List[Dict], chart_type: str) -> List[Dict]: + """Validate and ensure chart data matches frontend expectations""" + if not data or not isinstance(data, list): + return [] + + validated_data = [] + for item in data: + if not isinstance(item, dict): + continue + + # Ensure each item has the required structure for frontend + validated_item = {} + + # For pie charts, ensure name and value + if chart_type == "pie": + validated_item["name"] = str(item.get("name", item.get("NodeType", "Unknown"))) + validated_item["value"] = float(item.get("value", item.get("Count", item.get("count", 0)))) + + # For bar/line charts, preserve the structure but ensure proper types + else: + for key, value in item.items(): + if isinstance(value, (int, float)): + validated_item[key] = float(value) + elif isinstance(value, str): + validated_item[key] = value + elif isinstance(value, list): + # Convert lists to strings for display + validated_item[key] = str(value[0]) if value else "" + else: + validated_item[key] = str(value) if value is not None else "" + + validated_data.append(validated_item) + + return validated_data + + def _infer_chart_type_from_query(self, query: str) -> str: + """Infer chart type from user query""" + query_lower = query.lower() + + # Check for pie chart keywords + pie_keywords = ["pie", "proportion", "percentage", "part", "whole", "distribution", "share"] + if any(keyword in query_lower for keyword in pie_keywords): + return "pie" + + # Check for line chart keywords + line_keywords = ["line", "trend", "time", "series", "change", "over time", "progression", "growth", "decline"] + if any(keyword in query_lower for keyword in line_keywords): + return "line" + + # Default to bar chart for comparisons, categories, rankings, counts + return "bar" + + def _create_fallback_react_component(self, query: str, raw_data: List[Dict]) -> str: + """Create a simple fallback React component when LLM fails""" + try: + logger.info(f"Creating fallback React component for query: {query}") + logger.info(f"Raw data length: {len(raw_data) if raw_data else 0}") + + if not raw_data: + logger.error("No raw data available for fallback component") + return None + + # Process the data + chart_data = [] + for i, row in enumerate(raw_data[:20]): # Limit to first 20 items + logger.info(f"Processing row {i}: {row}") + # Handle different field names + name = row.get('name') or row.get('NodeType') or 'Unknown' + if isinstance(name, list): + name = ' '.join(name) if name else 'Unknown' + else: + name = str(name) + + count = row.get('count') or row.get('Count') or row.get('value') or 0 + chart_data.append({'name': name, 'value': count}) + logger.info(f"Processed: name='{name}', value={count}") + + logger.info(f"Final chart_data: {chart_data}") + + if not chart_data: + logger.error("No chart data generated from raw data") + return None + + # Generate colors + colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD', '#98D8C8', '#F7DC6F'] + + # Create React component using React.createElement + react_component = f'''// Note: React and Recharts are already imported in the iframe +const ChartComponent = () => {{ + const data = {chart_data}; + + return React.createElement('div', {{ className: 'w-full h-full p-4 bg-white rounded-lg shadow-lg' }}, + React.createElement('h3', {{ className: 'text-xl font-bold text-gray-800 mb-4 text-center' }}, '{query}'), + React.createElement(ResponsiveContainer, {{ width: '100%', height: 400 }}, + React.createElement(BarChart, {{ data: data, margin: {{ top: 5, right: 30, left: 20, bottom: 5 }} }}, + React.createElement(CartesianGrid, {{ strokeDasharray: '3 3' }}), + React.createElement(XAxis, {{ + dataKey: 'name', + angle: -45, + textAnchor: 'end', + height: 80, + interval: 0 + }}), + React.createElement(YAxis), + React.createElement(Tooltip), + React.createElement(Legend), + React.createElement(Bar, {{ + dataKey: 'value', + fill: '#8884d8', + radius: [4, 4, 0, 0] + }}) + ) + ) + ); +}};''' + + return react_component + + except Exception as e: + logger.error(f"Error creating fallback React component: {e}") + return None + + def _fix_jsx_syntax(self, react_content: str) -> str: + """Fix common JSX syntax issues in React components""" + try: + # Fix missing quotes around JSX attributes + import re + + # Fix height={400} -> height={{400}} + react_content = re.sub(r'height=(\d+)', r'height={{\1}}', react_content) + react_content = re.sub(r'width=(\d+)', r'width={{\1}}', react_content) + react_content = re.sub(r'angle=(-?\d+)', r'angle={{\1}}', react_content) + react_content = re.sub(r'interval=(\d+)', r'interval={{\1}}', react_content) + + # Fix radius=[4, 4, 0, 0] -> radius={{[4, 4, 0, 0]}} + react_content = re.sub(r'radius=\[([^\]]+)\]', r'radius={{\[\1\]}}', react_content) + + # Fix data={data} -> data={{data}} + react_content = re.sub(r'data=\{data\}', r'data={{{data}}}', react_content) + + # Fix margin={{ top: 5, right: 30, left: 20, bottom: 5 }} -> margin={{{ top: 5, right: 30, left: 20, bottom: 5 }}} + react_content = re.sub(r'margin=\{\{([^}]+)\}\}', r'margin={{{{\1}}}}', react_content) + + return react_content + + except Exception as e: + logger.error(f"Error fixing JSX syntax: {e}") + return react_content + + def _remove_import_statements(self, react_content: str) -> str: + """Remove any import statements from the React component""" + try: + import re + + # Remove import statements + react_content = re.sub(r'^import\s+.*?from\s+[\'"][^\'"]+[\'"];?\s*$', '', react_content, flags=re.MULTILINE) + react_content = re.sub(r'^import\s+[\'"][^\'"]+[\'"];?\s*$', '', react_content, flags=re.MULTILINE) + + # Remove export statements + react_content = re.sub(r'^export\s+.*?;?\s*$', '', react_content, flags=re.MULTILINE) + + # Clean up extra whitespace + react_content = re.sub(r'\n\s*\n\s*\n', '\n\n', react_content) + react_content = react_content.strip() + + logger.info(f"Removed import/export statements. New length: {len(react_content)}") + + return react_content + + except Exception as e: + logger.error(f"Error removing import statements: {e}") + return react_content + + def _convert_jsx_to_react_create_element(self, react_content: str) -> str: + """Convert JSX syntax to React.createElement calls""" + try: + import re + + # Check if the content contains JSX syntax + if '<' in react_content and '>' in react_content: + logger.warning("JSX syntax detected, attempting to convert to React.createElement") + + # This is a basic conversion - for complex JSX, we might need a more sophisticated approach + # For now, we'll just log a warning and return the content as-is + # The iframe should handle JSX with Babel transpilation + + logger.info("JSX detected but keeping as-is for Babel transpilation") + return react_content + + return react_content + + except Exception as e: + logger.error(f"Error converting JSX to React.createElement: {e}") + return react_content + +# Global MCP service instance +mcp_service = MCPNeo4jService() diff --git a/backend/src/monitoring_service.py b/backend/src/monitoring_service.py new file mode 100644 index 000000000..86a86dcd5 --- /dev/null +++ b/backend/src/monitoring_service.py @@ -0,0 +1,548 @@ +""" +Monitoring Service for tracking entities and detecting risk changes +""" + +import logging +from datetime import datetime +from typing import List, Dict, Any, Optional +from .llm import get_llm +from .graph_query import search_and_get_subgraph +import json +import uuid + +class MonitoringService: + def __init__(self, graph): + self.graph = graph + self.logger = logging.getLogger(__name__) + + def get_monitored_entities(self) -> List[Dict[str, Any]]: + """Get hardcoded list of monitored entities - can be moved to config later""" + return [ + { + "id": "entity_1", + "name": "Bill Gates", + "type": "Individual", + "risk_threshold": 0.7, + "category": "Technology" + }, + { + "id": "entity_2", + "name": "Microsoft", + "type": "Organization", + "risk_threshold": 0.6, + "category": "Technology" + }, + { + "id": "entity_3", + "name": "OpenAI", + "type": "Organization", + "risk_threshold": 0.8, + "category": "AI" + } + ] + + async def initialize_monitoring_schema(self): + """Initialize the monitoring schema in Neo4j if it doesn't exist""" + try: + # Create constraints and indexes for monitoring + schema_queries = [ + # Monitor constraints + "CREATE CONSTRAINT monitor_id_unique IF NOT EXISTS FOR (m:Monitor) REQUIRE m.id IS UNIQUE", + "CREATE INDEX monitor_entity_name IF NOT EXISTS FOR (m:Monitor) ON (m.entity_name)", + "CREATE INDEX monitor_status IF NOT EXISTS FOR (m:Monitor) ON (m.status)", + + # Risk Assessment constraints + "CREATE CONSTRAINT assessment_id_unique IF NOT EXISTS FOR (ra:RiskAssessment) REQUIRE ra.id IS UNIQUE", + "CREATE INDEX assessment_entity_name IF NOT EXISTS FOR (ra:RiskAssessment) ON (ra.entity_name)", + "CREATE INDEX assessment_timestamp IF NOT EXISTS FOR (ra:RiskAssessment) ON (ra.timestamp)", + + # Alert constraints + "CREATE CONSTRAINT alert_id_unique IF NOT EXISTS FOR (a:Alert) REQUIRE a.id IS UNIQUE", + "CREATE INDEX alert_entity_name IF NOT EXISTS FOR (a:Alert) ON (a.entity_name)", + "CREATE INDEX alert_timestamp IF NOT EXISTS FOR (a:Alert) ON (a.timestamp)" + ] + + for query in schema_queries: + try: + self.graph.query(query) + except Exception as e: + # Index/constraint might already exist, continue + self.logger.debug(f"Schema query result: {e}") + + self.logger.info("Monitoring schema initialized successfully") + + except Exception as e: + self.logger.error(f"Error initializing monitoring schema: {str(e)}") + + def store_monitored_entity(self, entity_data: Dict[str, Any]) -> str: + """Store a monitored entity in Neo4j""" + try: + entity_id = entity_data.get("id") or f"monitor_{uuid.uuid4()}" + + query = """ + MERGE (m:Monitor {id: $id}) + SET m.entity_name = $name, + m.entity_type = $type, + m.risk_threshold = $threshold, + m.category = $category, + m.status = $status, + m.created_at = $created_at, + m.updated_at = $updated_at + RETURN m.id as id + """ + + params = { + "id": entity_id, + "name": entity_data["name"], + "type": entity_data["type"], + "threshold": entity_data["risk_threshold"], + "category": entity_data["category"], + "status": entity_data.get("status", "active"), + "created_at": datetime.now().isoformat(), + "updated_at": datetime.now().isoformat() + } + + result = self.graph.query(query, params) + if result: + self.logger.info(f"Stored monitored entity: {entity_data['name']}") + return entity_id + else: + raise Exception("Failed to store monitored entity") + + except Exception as e: + self.logger.error(f"Error storing monitored entity: {str(e)}") + raise e + + def get_monitored_entities_from_db(self) -> List[Dict[str, Any]]: + """Retrieve all monitored entities from Neo4j""" + try: + query = """ + MATCH (m:Monitor) + RETURN m.id as id, m.entity_name as name, m.entity_type as type, + m.risk_threshold as risk_threshold, m.category as category, + m.status as status, m.created_at as created_at + ORDER BY m.created_at DESC + """ + + result = self.graph.query(query) + entities = [] + + for row in result: + entities.append({ + "id": row["id"], + "name": row["name"], + "type": row["type"], + "risk_threshold": row["risk_threshold"], + "category": row["category"], + "status": row["status"], + "created_at": row["created_at"] + }) + + return entities + + except Exception as e: + self.logger.error(f"Error retrieving monitored entities: {str(e)}") + return [] + + async def check_entity_risk_changes(self, monitored_entities: List[str], model: str = "openai_gpt_4o") -> Dict[str, Any]: + """ + Check if risk has increased for monitored entities based on new graph data + This is triggered after each document upload/URL scan + """ + try: + self.logger.info(f"Checking risk changes for {len(monitored_entities)} monitored entities") + + # Initialize schema if needed + await self.initialize_monitoring_schema() + + results = { + "timestamp": datetime.now().isoformat(), + "entities_checked": len(monitored_entities), + "risk_changes": [], + "alerts": [] + } + + for entity_name in monitored_entities: + try: + # Get current risk assessment for the entity + current_risk = await self._assess_entity_risk(entity_name, model) + + # Get previous risk assessment from storage + previous_risk = await self._get_previous_risk_assessment(entity_name) + + # Compare and detect changes + risk_change = self._detect_risk_change(entity_name, previous_risk, current_risk) + + if risk_change: + results["risk_changes"].append(risk_change) + + # Create alert if risk increased significantly + if risk_change.get("risk_increased", False): + alert = await self._create_and_store_alert(entity_name, risk_change) + results["alerts"].append(alert) + + # Store current assessment for future comparison + await self._store_risk_assessment(entity_name, current_risk) + + except Exception as e: + self.logger.error(f"Error checking entity {entity_name}: {str(e)}") + continue + + return results + + except Exception as e: + self.logger.error(f"Error in check_entity_risk_changes: {str(e)}") + return { + "error": str(e), + "timestamp": datetime.now().isoformat() + } + + async def _assess_entity_risk(self, entity_name: str, model: str) -> Dict[str, Any]: + """Assess current risk for an entity using existing graph data""" + try: + # Use existing graph query to get entity subgraph + try: + subgraph_result = await search_and_get_subgraph( + self.graph, + entity_name, + "Entity", + depth=3, + max_results=20 + ) + except Exception as e: + self.logger.warning(f"Could not get subgraph for {entity_name}: {str(e)}") + # Return basic assessment if subgraph query fails + return { + "entity_name": entity_name, + "risk_score": 0.1, # Low risk as fallback + "risk_level": "LOW", + "connections_count": 0, + "risk_indicators": [], + "new_connections": [], + "timestamp": datetime.now().isoformat(), + "error": f"Subgraph query failed: {str(e)}" + } + + if not subgraph_result or not subgraph_result.get("subgraphs"): + return { + "entity_name": entity_name, + "risk_score": 0.0, + "risk_level": "UNKNOWN", + "connections_count": 0, + "new_connections": [], + "timestamp": datetime.now().isoformat() + } + + # Extract relevant information from subgraph + subgraph = subgraph_result["subgraphs"][0] + nodes = subgraph.get("nodes", []) + relationships = subgraph.get("relationships", []) + + # Count connections and analyze risk indicators + connections_count = len(relationships) + risk_indicators = self._extract_risk_indicators(nodes, relationships) + + # Calculate risk score based on connections and indicators + risk_score = self._calculate_risk_score(connections_count, risk_indicators) + risk_level = self._get_risk_level(risk_score) + + return { + "entity_name": entity_name, + "risk_score": risk_score, + "risk_level": risk_level, + "connections_count": connections_count, + "risk_indicators": risk_indicators, + "new_connections": [], # Will be populated by comparison + "timestamp": datetime.now().isoformat() + } + + except Exception as e: + self.logger.error(f"Error assessing risk for {entity_name}: {str(e)}") + return { + "entity_name": entity_name, + "risk_score": 0.0, + "risk_level": "UNKNOWN", + "error": str(e), + "timestamp": datetime.now().isoformat() + } + + def _extract_risk_indicators(self, nodes: List[Dict], relationships: List[Dict]) -> List[str]: + """Extract risk indicators from graph nodes and relationships""" + risk_indicators = [] + + # Look for risk-related properties and labels + for node in nodes: + labels = node.get("labels", []) + properties = node.get("properties", {}) + + # Check for risk-related labels + if any(label.lower() in ["risk", "threat", "suspicious", "sanction"] for label in labels): + risk_indicators.append(f"Risk-related node: {node.get('properties', {}).get('name', 'Unknown')}") + + # Check for risk-related properties + for key, value in properties.items(): + if isinstance(value, str) and any(term in value.lower() for term in ["risk", "threat", "suspicious", "sanction"]): + risk_indicators.append(f"Risk indicator in {key}: {value}") + + # Check relationships for risk patterns + for rel in relationships: + rel_type = rel.get("type", "") + if any(term in rel_type.lower() for term in ["risk", "threat", "suspicious"]): + risk_indicators.append(f"Risk relationship: {rel_type}") + + return risk_indicators + + def _calculate_risk_score(self, connections_count: int, risk_indicators: List[str]) -> float: + """Calculate risk score based on connections and indicators""" + base_score = min(connections_count * 0.1, 0.5) # Base score from connections + + indicator_score = min(len(risk_indicators) * 0.2, 0.5) # Score from risk indicators + + total_score = base_score + indicator_score + + # Normalize to 0.0 - 1.0 range + return min(total_score, 1.0) + + def _get_risk_level(self, risk_score: float) -> str: + """Convert risk score to risk level""" + if risk_score >= 0.7: + return "HIGH" + elif risk_score >= 0.4: + return "MEDIUM" + else: + return "LOW" + + def _detect_risk_change(self, entity_name: str, previous_risk: Optional[Dict], current_risk: Dict) -> Optional[Dict]: + """Detect if risk has changed for an entity""" + if not previous_risk: + return { + "entity_name": entity_name, + "change_type": "initial_assessment", + "previous_score": None, + "current_score": current_risk["risk_score"], + "score_change": 0, + "risk_increased": False, + "details": "First risk assessment" + } + + previous_score = previous_risk.get("risk_score", 0.0) + current_score = current_risk["risk_score"] + score_change = current_score - previous_score + + # Determine if risk increased significantly (more than 20%) + risk_increased = score_change > 0.2 + + # Check for new connections + previous_connections = previous_risk.get("connections_count", 0) + current_connections = current_risk.get("connections_count", 0) + new_connections = current_connections - previous_connections + + return { + "entity_name": entity_name, + "change_type": "risk_change", + "previous_score": previous_score, + "current_score": current_score, + "score_change": score_change, + "risk_increased": risk_increased, + "connections_change": new_connections, + "details": f"Risk score changed from {previous_score:.2f} to {current_score:.2f}" + } + + async def _create_and_store_alert(self, entity_name: str, risk_change: Dict) -> Dict[str, Any]: + """Create and store an alert for significant risk changes""" + try: + alert_id = f"alert_{uuid.uuid4()}" + alert_data = { + "id": alert_id, + "entity_name": entity_name, + "type": "risk_increase" if risk_change.get("risk_increased") else "risk_change", + "severity": "high" if risk_change.get("risk_increased") else "medium", + "title": f"Risk Change Detected: {entity_name}", + "description": risk_change.get("details", "Risk level has changed"), + "timestamp": datetime.now().isoformat(), + "risk_change": risk_change + } + + # Store alert in Neo4j + query = """ + CREATE (a:Alert { + id: $id, + entity_name: $entity_name, + type: $type, + severity: $severity, + title: $title, + description: $description, + timestamp: $timestamp, + risk_change_data: $risk_change_data + }) + RETURN a.id as id + """ + + params = { + "id": alert_id, + "entity_name": entity_name, + "type": alert_data["type"], + "severity": alert_data["severity"], + "title": alert_data["title"], + "description": alert_data["description"], + "timestamp": alert_data["timestamp"], + "risk_change_data": json.dumps(risk_change) + } + + result = await self.graph.query(query, params) + if result: + self.logger.info(f"Stored alert for {entity_name}: {alert_id}") + return alert_data + else: + raise Exception("Failed to store alert") + + except Exception as e: + self.logger.error(f"Error creating alert: {str(e)}") + # Return alert data even if storage fails + return { + "id": f"alert_{datetime.now().timestamp()}", + "entity_name": entity_name, + "type": "risk_increase" if risk_change.get("risk_increased") else "risk_change", + "severity": "high" if risk_change.get("risk_increased") else "medium", + "title": f"Risk Change Detected: {entity_name}", + "description": risk_change.get("details", "Risk level has changed"), + "timestamp": datetime.now().isoformat(), + "risk_change": risk_change + } + + async def _get_previous_risk_assessment(self, entity_name: str) -> Optional[Dict]: + """Get previous risk assessment from Neo4j storage""" + try: + query = """ + MATCH (ra:RiskAssessment {entity_name: $entity_name}) + RETURN ra.risk_score as risk_score, ra.risk_level as risk_level, + ra.connections_count as connections_count, ra.risk_indicators as risk_indicators, + ra.timestamp as timestamp + ORDER BY ra.timestamp DESC + LIMIT 1 + """ + + result = self.graph.query(query, {"entity_name": entity_name}) + + if result: + row = result[0] + return { + "risk_score": row["risk_score"], + "risk_level": row["risk_level"], + "connections_count": row["connections_count"], + "risk_indicators": row["risk_indicators"] if row["risk_indicators"] else [], + "timestamp": row["timestamp"] + } + else: + return None + + except Exception as e: + self.logger.error(f"Error retrieving previous risk assessment for {entity_name}: {str(e)}") + return None + + async def _store_risk_assessment(self, entity_name: str, assessment: Dict): + """Store current risk assessment in Neo4j for future comparison""" + try: + assessment_id = f"assessment_{uuid.uuid4()}" + + query = """ + CREATE (ra:RiskAssessment { + id: $id, + entity_name: $entity_name, + risk_score: $risk_score, + risk_level: $risk_level, + connections_count: $connections_count, + risk_indicators: $risk_indicators, + timestamp: $timestamp + }) + """ + + params = { + "id": assessment_id, + "entity_name": entity_name, + "risk_score": assessment["risk_score"], + "risk_level": assessment["risk_level"], + "connections_count": assessment["connections_count"], + "risk_indicators": assessment.get("risk_indicators", []), + "timestamp": assessment["timestamp"] + } + + self.graph.query(query, params) + self.logger.info(f"Stored risk assessment for {entity_name}: {assessment_id}") + + except Exception as e: + self.logger.error(f"Error storing risk assessment for {entity_name}: {str(e)}") + # Continue execution even if storage fails + pass + + def remove_monitored_entity(self, entity_id: str) -> bool: + """Remove a monitored entity from Neo4j""" + try: + self.logger.info(f"Attempting to remove monitored entity with ID: {entity_id}") + + # First, let's check if the entity exists + check_query = """ + MATCH (m:Monitor {id: $entity_id}) + RETURN m.id as id, m.entity_name as name + """ + + check_result = self.graph.query(check_query, {"entity_id": entity_id}) + self.logger.info(f"Check query result: {check_result}") + + if not check_result: + self.logger.warning(f"Entity not found with ID: {entity_id}") + return False + + # Remove the monitor node and related data + query = """ + MATCH (m:Monitor {id: $entity_id}) + OPTIONAL MATCH (ra:RiskAssessment {entity_name: m.entity_name}) + OPTIONAL MATCH (a:Alert {entity_name: m.entity_name}) + DELETE m, ra, a + RETURN count(m) as deleted_count + """ + + result = self.graph.query(query, {"entity_id": entity_id}) + self.logger.info(f"Delete query result: {result}") + + if result and result[0]["deleted_count"] > 0: + self.logger.info(f"Successfully removed monitored entity: {entity_id}") + return True + else: + self.logger.warning(f"Failed to delete entity: {entity_id}") + return False + + except Exception as e: + self.logger.error(f"Error removing monitored entity {entity_id}: {str(e)}") + return False + + def get_monitoring_alerts(self) -> List[Dict]: + """Get all monitoring alerts from Neo4j""" + try: + query = """ + MATCH (a:Alert) + RETURN a.id as id, a.entity_name as entity_name, + a.severity as severity, a.message as message, + a.timestamp as timestamp + ORDER BY a.timestamp DESC + """ + + result = self.graph.query(query) + + if result: + alerts = [] + for record in result: + alerts.append({ + "id": record["id"], + "entity_name": record["entity_name"], + "severity": record["severity"], + "message": record["message"], + "timestamp": record["timestamp"] + }) + return alerts + else: + return [] + + except Exception as e: + self.logger.error(f"Error getting monitoring alerts: {str(e)}") + return [] diff --git a/backend/src/monitoring_service_pg.py b/backend/src/monitoring_service_pg.py new file mode 100644 index 000000000..726847e4c --- /dev/null +++ b/backend/src/monitoring_service_pg.py @@ -0,0 +1,689 @@ +""" +PostgreSQL-based Monitoring Service for entity monitoring and risk assessment +""" + +import uuid +import logging +from datetime import datetime +from typing import Dict, List, Any, Optional +from src.database import DatabaseManager + +logger = logging.getLogger(__name__) + +class MonitoringServicePG: + def __init__(self): + self.db = DatabaseManager() + self.logger = logger + + def initialize_monitoring_schema(self) -> bool: + """Initialize monitoring schema (tables are created by migrations)""" + try: + # Test if tables exist by running a simple query + result = self.db.execute_query(""" + SELECT table_name + FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name IN ('monitored_entities', 'risk_assessments', 'alerts') + """) + + if len(result) == 3: + self.logger.info("Monitoring schema already exists") + return True + else: + self.logger.warning("Monitoring schema not fully initialized. Run migrations first.") + return False + + except Exception as e: + self.logger.error(f"Error checking monitoring schema: {str(e)}") + return False + + def store_monitored_entity(self, entity_data: Dict[str, Any]) -> int: + """Store a monitored entity in PostgreSQL""" + try: + query = """ + INSERT INTO monitored_entities (name, type, risk_threshold, category, status, created_at, updated_at) + VALUES (%s, %s, %s, %s, %s, %s, %s) + RETURNING id + """ + + params = ( + entity_data["name"], + entity_data["type"], + entity_data.get("risk_threshold", 0.7), + entity_data.get("category", "General"), + entity_data.get("status", "active"), + datetime.now(), + datetime.now() + ) + + # For INSERT with RETURNING, use the specialized method + result = self.db.execute_insert_returning(query, params) + if result: + entity_id = result[0]["id"] + self.logger.info(f"Stored monitored entity: {entity_data['name']} with ID: {entity_id}") + return entity_id + else: + raise Exception("Failed to store monitored entity") + + except Exception as e: + self.logger.error(f"Error storing monitored entity: {str(e)}") + raise e + + def get_monitored_entities_from_db(self) -> List[Dict[str, Any]]: + """Retrieve all monitored entities from PostgreSQL""" + try: + query = """ + SELECT id, name, type, risk_threshold, category, status, created_at + FROM monitored_entities + ORDER BY created_at DESC + """ + + result = self.db.execute_query(query) + entities = [] + + for row in result: + entities.append({ + "id": row["id"], + "name": row["name"], + "type": row["type"], + "risk_threshold": float(row["risk_threshold"]) if row["risk_threshold"] else 0.7, + "category": row["category"], + "status": row["status"], + "created_at": row["created_at"].isoformat() if row["created_at"] else None + }) + + return entities + + except Exception as e: + self.logger.error(f"Error retrieving monitored entities: {str(e)}") + return [] + + def remove_monitored_entity(self, entity_id: int) -> bool: + """Remove a monitored entity from PostgreSQL""" + try: + self.logger.info(f"Attempting to remove monitored entity with ID: {entity_id}") + + # First, check if the entity exists + check_query = """ + SELECT id, name FROM monitored_entities WHERE id = %s + """ + + check_result = self.db.execute_query(check_query, (entity_id,)) + self.logger.info(f"Check query result: {check_result}") + + if not check_result: + self.logger.warning(f"Entity not found with ID: {entity_id}") + return False + + # Remove related data first (due to foreign key constraints) + # Delete alerts + self.db.execute_command("DELETE FROM alerts WHERE entity_id = %s", (entity_id,)) + + # Delete risk assessments + self.db.execute_command("DELETE FROM risk_assessments WHERE entity_id = %s", (entity_id,)) + + # Delete the monitored entity + deleted_count = self.db.execute_command("DELETE FROM monitored_entities WHERE id = %s", (entity_id,)) + + if deleted_count > 0: + self.logger.info(f"Successfully removed monitored entity: {entity_id}") + return True + else: + self.logger.warning(f"Failed to delete entity: {entity_id}") + return False + + except Exception as e: + self.logger.error(f"Error removing monitored entity {entity_id}: {str(e)}") + return False + + def get_monitoring_alerts(self) -> List[Dict]: + """Get all monitoring alerts from PostgreSQL""" + try: + query = """ + SELECT a.id, a.severity, a.message, a.timestamp, a.is_active, + e.name as entity_name + FROM alerts a + JOIN monitored_entities e ON a.entity_id = e.id + ORDER BY a.timestamp DESC + """ + + result = self.db.execute_query(query) + + if result: + alerts = [] + for record in result: + alerts.append({ + "id": record["id"], + "entity_name": record["entity_name"], + "severity": record["severity"], + "message": record["message"], + "timestamp": record["timestamp"].isoformat() if record["timestamp"] else None, + "is_active": record["is_active"] + }) + return alerts + else: + return [] + + except Exception as e: + self.logger.error(f"Error getting monitoring alerts: {str(e)}") + return [] + + def store_risk_assessment(self, entity_id: int, assessment: Dict) -> int: + """Store a risk assessment in PostgreSQL""" + try: + query = """ + INSERT INTO risk_assessments (entity_id, risk_score, risk_level, connections_count, risk_indicators, timestamp) + VALUES (%s, %s, %s, %s, %s, %s) + RETURNING id + """ + + params = ( + entity_id, + assessment["risk_score"], + assessment["risk_level"], + assessment.get("connections_count", 0), + assessment.get("risk_indicators", []), + datetime.now() + ) + + result = self.db.execute_insert_returning(query, params) + if result: + assessment_id = result[0]["id"] + self.logger.info(f"Stored risk assessment for entity {entity_id}: {assessment_id}") + return assessment_id + else: + raise Exception("Failed to store risk assessment") + + except Exception as e: + self.logger.error(f"Error storing risk assessment for entity {entity_id}: {str(e)}") + raise e + + def get_latest_risk_assessment(self, entity_id: int) -> Optional[Dict]: + """Get the latest risk assessment for an entity""" + try: + query = """ + SELECT id, risk_score, risk_level, connections_count, risk_indicators, timestamp + FROM risk_assessments + WHERE entity_id = %s + ORDER BY timestamp DESC + LIMIT 1 + """ + + result = self.db.execute_query(query, (entity_id,)) + + if result: + row = result[0] + return { + "id": row["id"], + "risk_score": float(row["risk_score"]), + "risk_level": row["risk_level"], + "connections_count": row["connections_count"], + "risk_indicators": row["risk_indicators"] or [], + "timestamp": row["timestamp"].isoformat() if row["timestamp"] else None + } + else: + return None + + except Exception as e: + self.logger.error(f"Error retrieving risk assessment for entity {entity_id}: {str(e)}") + return None + + def create_alert(self, entity_id: int, alert_data: Dict[str, Any]) -> int: + """Create a new alert in PostgreSQL with LLM alert structure""" + try: + query = """ + INSERT INTO alerts (entity_id, type, score, message, evidence, indicator, name, context, timestamp, is_active) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + RETURNING id + """ + + params = ( + entity_id, + alert_data.get("type", "HIGH_RISK"), + alert_data.get("score", 0.5), + alert_data.get("description", ""), + alert_data.get("evidence", ""), + alert_data.get("indicator", ""), + alert_data.get("name", ""), + alert_data.get("context", ""), + datetime.now(), + True + ) + + result = self.db.execute_insert_returning(query, params) + if result: + alert_id = result[0]["id"] + self.logger.info(f"Created alert {alert_id} for entity {entity_id}: {alert_data.get('type', 'HIGH_RISK')}") + return alert_id + else: + raise Exception("Failed to create alert") + + except Exception as e: + self.logger.error(f"Error creating alert for entity {entity_id}: {str(e)}") + raise e + + def get_entity_by_name(self, entity_name: str) -> Optional[Dict]: + """Get entity by name with fuzzy matching""" + try: + # First try exact match + query = """ + SELECT id, name, type, risk_threshold, category, status + FROM monitored_entities + WHERE name = %s + """ + + result = self.db.execute_query(query, (entity_name,)) + + if result: + return result[0] + + # If no exact match, try case-insensitive partial matching + query = """ + SELECT id, name, type, risk_threshold, category, status + FROM monitored_entities + WHERE LOWER(name) LIKE LOWER(%s) + """ + + result = self.db.execute_query(query, (f"%{entity_name}%",)) + + if result: + row = result[0] + return { + "id": row["id"], + "name": row["name"], + "type": row["type"], + "risk_threshold": float(row["risk_threshold"]) if row["risk_threshold"] else 0.7, + "category": row["category"], + "status": row["status"] + } + else: + return None + + except Exception as e: + self.logger.error(f"Error retrieving entity by name {entity_name}: {str(e)}") + return None + + def update_entity_status(self, entity_id: int, status: str) -> bool: + """Update entity status""" + try: + query = """ + UPDATE monitored_entities + SET status = %s, updated_at = %s + WHERE id = %s + """ + + affected_rows = self.db.execute_command(query, (status, datetime.now(), entity_id)) + return affected_rows > 0 + + except Exception as e: + self.logger.error(f"Error updating entity status: {str(e)}") + return False + + def get_active_alerts_count(self) -> int: + """Get count of active alerts""" + try: + query = "SELECT COUNT(*) as count FROM alerts WHERE is_active = true" + result = self.db.execute_query(query) + return result[0]["count"] if result else 0 + except Exception as e: + self.logger.error(f"Error getting active alerts count: {str(e)}") + return 0 + + def get_alerts_today_count(self) -> int: + """Get count of alerts created today""" + try: + query = """ + SELECT COUNT(*) as count + FROM alerts + WHERE DATE(timestamp) = CURRENT_DATE + """ + result = self.db.execute_query(query) + return result[0]["count"] if result else 0 + except Exception as e: + self.logger.error(f"Error getting today's alerts count: {str(e)}") + return 0 + + def acknowledge_alert(self, alert_id: int) -> bool: + """Mark an alert as acknowledged (inactive)""" + try: + query = """ + UPDATE alerts + SET is_active = FALSE + WHERE id = %s + """ + + result = self.db.execute_command(query, (alert_id,)) + if result > 0: + self.logger.info(f"Alert {alert_id} acknowledged successfully") + return True + else: + self.logger.warning(f"Alert {alert_id} not found or already acknowledged") + return False + + except Exception as e: + self.logger.error(f"Error acknowledging alert {alert_id}: {str(e)}") + return False + + def get_active_alerts_from_db(self) -> List[Dict[str, Any]]: + """Retrieve only active (unacknowledged) alerts from PostgreSQL""" + try: + query = """ + SELECT a.id, a.severity, a.message, a.timestamp, a.is_active, + me.name as entity_name + FROM alerts a + LEFT JOIN monitored_entities me ON a.entity_id = me.id + WHERE a.is_active = TRUE + ORDER BY a.timestamp DESC + """ + + result = self.db.execute_query(query) + active_alerts = [] + + for row in result: + active_alerts.append({ + "id": row["id"], + "entity_name": row["name"] or "Unknown Entity", + "severity": row["severity"], + "message": row["message"], + "timestamp": row["timestamp"].isoformat() if row["timestamp"] else None, + "is_active": row["is_active"] if row["is_active"] is not None else True + }) + + return active_alerts + + except Exception as e: + self.logger.error(f"Error retrieving active alerts: {str(e)}") + return [] + + async def check_entity_risk_changes(self, monitored_entities: List[str], model: str = "openai_gpt_4o", graph_connection=None) -> Dict[str, Any]: + """ + Enhanced risk monitoring: Analyze sub-graphs and generate LLM-based alerts + """ + try: + self.logger.info(f"Enhanced risk monitoring for {len(monitored_entities)} entities using model: {model}") + + result = { + "entities_checked": len(monitored_entities), + "risk_changes_detected": 0, + "alerts_generated": 0, + "entities_with_changes": [], + "model_used": model, + "timestamp": datetime.now().isoformat() + } + + if not graph_connection: + self.logger.warning("No graph connection provided, using basic monitoring") + return await self._basic_risk_check(monitored_entities, model) + + # Enhanced monitoring with graph analysis + for entity_name in monitored_entities: + entity = self.get_entity_by_name(entity_name) + if not entity: + self.logger.warning(f"Entity not found in monitoring: {entity_name}") + continue + + try: + # Get current sub-graph for entity + current_subgraph = await self._get_entity_subgraph(graph_connection, entity_name) + + # Get previous risk assessment + previous_assessment = self.get_latest_risk_assessment(entity["id"]) + + # Analyze risk changes + risk_analysis = await self._analyze_entity_risk_changes( + entity, current_subgraph, previous_assessment, model + ) + + # Store new risk assessment + if risk_analysis["current_risk_score"] is not None: + self.store_risk_assessment( + entity["id"], + risk_analysis["current_risk_score"], + risk_analysis["risk_level"], + risk_analysis["connections_count"], + risk_analysis["risk_indicators"] + ) + + # Generate alert if risk increased + if risk_analysis["risk_increased"]: + alert_message = await self._generate_llm_alert( + entity, risk_analysis, current_subgraph, model + ) + + if alert_message: + alert_id = self.create_alert( + entity["id"], + risk_analysis["alert_severity"], + alert_message + ) + result["alerts_generated"] += 1 + self.logger.info(f"Generated alert {alert_id} for {entity_name}") + + # Add to results + result["entities_with_changes"].append({ + "name": entity_name, + "id": entity["id"], + "current_risk": risk_analysis["current_risk_score"], + "risk_level": risk_analysis["risk_level"], + "risk_change": risk_analysis["risk_change_description"], + "connections_count": risk_analysis["connections_count"], + "alert_generated": risk_analysis["risk_increased"] + }) + + if risk_analysis["risk_increased"]: + result["risk_changes_detected"] += 1 + + except Exception as e: + self.logger.error(f"Error analyzing entity {entity_name}: {str(e)}") + result["entities_with_changes"].append({ + "name": entity_name, + "id": entity["id"], + "current_risk": "error", + "risk_change": f"Error: {str(e)}" + }) + + self.logger.info(f"Enhanced risk monitoring completed. Result: {result}") + return result + + except Exception as e: + self.logger.error(f"Error in enhanced risk monitoring: {str(e)}") + return { + "error": str(e), + "entities_checked": 0, + "risk_changes_detected": 0, + "alerts_generated": 0 + } + + async def _basic_risk_check(self, monitored_entities: List[str], model: str) -> Dict[str, Any]: + """Basic risk check when no graph connection is available""" + result = { + "entities_checked": len(monitored_entities), + "risk_changes_detected": 0, + "alerts_generated": 0, + "entities_with_changes": [], + "model_used": model, + "timestamp": datetime.now().isoformat() + } + + for entity_name in monitored_entities: + entity = self.get_entity_by_name(entity_name) + if entity: + result["entities_with_changes"].append({ + "name": entity_name, + "id": entity["id"], + "current_risk": "unknown", + "risk_change": "no_change_detected" + }) + else: + self.logger.warning(f"Entity not found in monitoring: {entity_name}") + + return result + + async def _get_entity_subgraph(self, graph_connection, entity_name: str) -> Dict[str, Any]: + """Extract sub-graph for a specific entity""" + try: + # Cypher query to get entity sub-graph + query = """ + MATCH (e:Entity {name: $entity_name}) + OPTIONAL MATCH (e)-[r]-(related) + RETURN e, r, related + LIMIT 100 + """ + + result = graph_connection.query(query, {"entity_name": entity_name}) + + # Process sub-graph data + subgraph = { + "entity": entity_name, + "connections": [], + "total_connections": 0, + "risk_indicators": [] + } + + if result: + for record in result: + if "r" in record and record["r"]: + connection = { + "type": record["r"].type, + "properties": dict(record["r"]), + "related_node": record["related"].get("name", "Unknown") if record["related"] else None + } + subgraph["connections"].append(connection) + + subgraph["total_connections"] = len(subgraph["connections"]) + + # Extract risk indicators from connections + risk_indicators = [] + for conn in subgraph["connections"]: + if conn["type"] in ["HAS_RISK", "ASSOCIATED_WITH", "CONNECTED_TO"]: + risk_indicators.append(conn["type"]) + + subgraph["risk_indicators"] = list(set(risk_indicators)) + + return subgraph + + except Exception as e: + self.logger.error(f"Error getting sub-graph for {entity_name}: {str(e)}") + return {"entity": entity_name, "connections": [], "total_connections": 0, "risk_indicators": []} + + async def _analyze_entity_risk_changes(self, entity: Dict, current_subgraph: Dict, previous_assessment: Optional[Dict], model: str) -> Dict[str, Any]: + """Analyze risk changes for an entity""" + try: + # Calculate current risk based on sub-graph + current_risk_score = self._calculate_risk_score(current_subgraph) + current_risk_level = self._get_risk_level(current_risk_score) + + # Compare with previous assessment + risk_increased = False + risk_change_description = "no_change" + alert_severity = "low" + + if previous_assessment: + previous_score = float(previous_assessment["risk_score"]) + previous_connections = previous_assessment["connections_count"] or 0 + + # Check if risk increased + if current_risk_score > previous_score: + risk_increased = True + risk_change_description = f"Risk increased from {previous_score:.2f} to {current_risk_score:.2f}" + + # Determine alert severity + if current_risk_score - previous_score > 0.3: + alert_severity = "critical" + elif current_risk_score - previous_score > 0.2: + alert_severity = "high" + elif current_risk_score - previous_score > 0.1: + alert_severity = "medium" + else: + alert_severity = "low" + + elif current_subgraph["total_connections"] > previous_connections: + risk_increased = True + risk_change_description = f"Connections increased from {previous_connections} to {current_subgraph['total_connections']}" + alert_severity = "medium" + + return { + "current_risk_score": current_risk_score, + "risk_level": current_risk_level, + "connections_count": current_subgraph["total_connections"], + "risk_indicators": current_subgraph["risk_indicators"], + "risk_increased": risk_increased, + "risk_change_description": risk_change_description, + "alert_severity": alert_severity + } + + except Exception as e: + self.logger.error(f"Error analyzing risk changes: {str(e)}") + return { + "current_risk_score": None, + "risk_level": "unknown", + "connections_count": 0, + "risk_indicators": [], + "risk_increased": False, + "risk_change_description": "error", + "alert_severity": "low" + } + + def _calculate_risk_score(self, subgraph: Dict) -> float: + """Calculate risk score based on sub-graph analysis""" + try: + base_score = 0.3 # Base risk score + + # Factor 1: Number of connections (more connections = higher risk) + connection_factor = min(subgraph["total_connections"] * 0.05, 0.4) + + # Factor 2: Risk indicators + risk_indicator_factor = len(subgraph["risk_indicators"]) * 0.1 + + # Factor 3: Connection types (certain types indicate higher risk) + high_risk_connections = sum(1 for conn in subgraph["connections"] + if conn["type"] in ["HAS_RISK", "ASSOCIATED_WITH"]) + high_risk_factor = high_risk_connections * 0.15 + + total_score = base_score + connection_factor + risk_indicator_factor + high_risk_factor + + # Cap at 1.0 + return min(total_score, 1.0) + + except Exception as e: + self.logger.error(f"Error calculating risk score: {str(e)}") + return 0.5 + + def _get_risk_level(self, risk_score: float) -> str: + """Convert risk score to risk level""" + if risk_score >= 0.8: + return "critical" + elif risk_score >= 0.6: + return "high" + elif risk_score >= 0.4: + return "medium" + else: + return "low" + + async def _generate_llm_alert(self, entity: Dict, risk_analysis: Dict, subgraph: Dict, model: str) -> str: + """Generate LLM-based alert message""" + try: + # This would integrate with your existing LLM system + # For now, return a structured alert message + + alert_template = f""" + RISK ALERT: {entity['name']} ({entity['type']}) + + Risk Level: {risk_analysis['risk_level'].upper()} + Current Risk Score: {risk_analysis['current_risk_score']:.2f} + Risk Change: {risk_analysis['risk_change_description']} + + Connections: {risk_analysis['connections_count']} + Risk Indicators: {', '.join(risk_analysis['risk_indicators']) if risk_analysis['risk_indicators'] else 'None detected'} + + Alert Severity: {risk_analysis['alert_severity'].upper()} + Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} + + This alert was generated automatically by the risk monitoring system. + """ + + return alert_template.strip() + + except Exception as e: + self.logger.error(f"Error generating LLM alert: {str(e)}") + return f"Risk alert generated for {entity['name']}: {risk_analysis['risk_change_description']}" diff --git a/backend/src/risk_assessment.py b/backend/src/risk_assessment.py new file mode 100644 index 000000000..bc729eac4 --- /dev/null +++ b/backend/src/risk_assessment.py @@ -0,0 +1,430 @@ +import logging +import json +import os +from typing import Dict, List, Any, Optional +from jinja2 import Template +from src.graph_query import search_and_get_subgraph, get_graphDB_driver +from src.llm import get_llm +from src.shared.constants import RISK_ASSESSMENT_PROMPT + +def extract_chunks_from_subgraph(subgraph_data: Dict[str, Any]) -> List[Dict[str, Any]]: + """ + Extract relevant chunks from subgraph data with enhanced URL extraction. + + Args: + subgraph_data: Subgraph data from search_and_get_subgraph + + Returns: + List of chunks with text and source information + """ + chunks = [] + documents = {} # Store document information for source URLs + + try: + logging.info(f"Extracting chunks from subgraph data: {len(subgraph_data.get('subgraphs', []))} subgraphs") + + # First pass: collect document information from subgraph + for subgraph in subgraph_data.get('subgraphs', []): + for node in subgraph.get('nodes', []): + node_labels = node.get('labels', []) + node_props = node.get('properties', {}) + + # Look for document nodes that might contain source URLs + if any(label in ['Document', 'File', 'Source'] for label in node_labels): + doc_id = node_props.get('id') or node_props.get('document_id') or node_props.get('name') + if doc_id: + documents[doc_id] = { + 'url': node_props.get('url', ''), + 'source': node_props.get('source', ''), + 'file_name': node_props.get('name', ''), + 'document_type': node_props.get('type', '') + } + logging.info(f"Found document: {doc_id} with URL: {documents[doc_id]['url']}") + + # Second pass: extract chunks and link to documents + for subgraph in subgraph_data.get('subgraphs', []): + logging.info(f"Processing subgraph with {len(subgraph.get('nodes', []))} nodes") + + for node in subgraph.get('nodes', []): + node_labels = node.get('labels', []) + node_props = node.get('properties', {}) + + # Check for chunk nodes - look for various possible chunk labels + is_chunk_node = any(label in ['Chunk', 'DocumentChunk', 'TextChunk'] for label in node_labels) + + # Also check if node has chunk-like properties + has_chunk_props = any(key in ['text', 'content', 'chunk_text'] for key in node_props.keys()) + + if is_chunk_node or has_chunk_props: + logging.info(f"Found chunk node: {node.get('element_id')} with labels: {node_labels}") + logging.info(f"Chunk node properties: {list(node_props.keys())}") + + # Try different possible property names for text content + text_content = ( + node_props.get('text') or + node_props.get('content') or + node_props.get('chunk_text') or + node_props.get('text_content') or + str(node_props) # Fallback to string representation + ) + + # Get document information - try multiple approaches + doc_id = node_props.get('document_id') or node_props.get('doc_id') + doc_info = documents.get(doc_id, {}) + + # Enhanced source extraction - try to get actual source URL + source_url = None + + # 1. First try chunk's own URL property (for new chunks with URL fix) + if node_props.get('url'): + source_url = node_props.get('url') + logging.info(f"Using chunk's own URL: {source_url}") + + # 2. Try to get URL from document info + elif doc_info.get('url'): + source_url = doc_info.get('url') + logging.info(f"Using document URL: {source_url}") + + # 3. Try to get URL from document name lookup + elif node_props.get('fileName'): + # Look for document with this fileName + for doc_id, doc_info in documents.items(): + if doc_info.get('file_name') == node_props.get('fileName'): + if doc_info.get('url'): + source_url = doc_info.get('url') + logging.info(f"Found URL via fileName lookup: {source_url}") + break + + # 4. Try other fallbacks + elif node_props.get('source_url'): + source_url = node_props.get('source_url') + elif doc_info.get('source'): + source_url = doc_info.get('source') + elif node_props.get('source'): + source_url = node_props.get('source') + + # 5. Construct source reference if no URL found + if not source_url: + if doc_info.get('file_name'): + source_url = f"Document: {doc_info['file_name']}" + elif node_props.get('fileName'): + source_url = f"Document: {node_props['fileName']}" + else: + source_url = f"Chunk {len(chunks) + 1}" + + # Validate URL format + if source_url and not source_url.startswith(('http://', 'https://', 'Document:', 'Source:', 'Chunk')): + # If it looks like a URL but doesn't have protocol, add https:// + if '.' in source_url and '/' in source_url: + source_url = f"https://{source_url}" + else: + source_url = f"Document: {source_url}" + + chunk_info = { + 'text': text_content, + 'source': source_url, + 'document_id': doc_id or '', + 'chunk_id': node_props.get('id', node.get('element_id', '')), + 'document_name': doc_info.get('file_name', ''), + 'document_type': doc_info.get('document_type', '') + } + + if chunk_info['text'] and len(chunk_info['text'].strip()) > 10: # Only add non-empty chunks with substantial content + chunks.append(chunk_info) + logging.info(f"Added chunk with {len(chunk_info['text'])} characters, source: {chunk_info['source']}") + + # Remove duplicates based on chunk_id + unique_chunks = [] + seen_ids = set() + for chunk in chunks: + if chunk['chunk_id'] not in seen_ids: + unique_chunks.append(chunk) + seen_ids.add(chunk['chunk_id']) + + logging.info(f"Extracted {len(unique_chunks)} unique chunks from subgraph") + return unique_chunks[:10] # Limit to 10 most relevant chunks + + except Exception as e: + logging.error(f"Error extracting chunks from subgraph: {str(e)}") + return [] + +def enhance_chunks_with_urls(uri: str, username: str, password: str, database: str, + chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]: + """ + Enhance chunks with URL information by querying the database for Document URLs. + + Args: + uri: Neo4j database URI + username: Database username + password: Database password + database: Database name + chunks: List of chunks to enhance + + Returns: + Enhanced chunks with URL information + """ + try: + from src.shared.common_fn import create_graph_database_connection, execute_graph_query + + # Connect to database + graph = create_graph_database_connection(uri, username, password, database) + + # Get unique file names from chunks + file_names = set() + for chunk in chunks: + if chunk.get('document_name'): + file_names.add(chunk['document_name']) + elif 'fileName' in chunk.get('source', ''): + # Extract fileName from source like "Document: Bill_Gates" + source = chunk['source'] + if source.startswith('Document: '): + file_names.add(source.replace('Document: ', '')) + + # Query database for Document URLs + if file_names: + placeholders = ', '.join([f"'{name}'" for name in file_names]) + url_query = f""" + MATCH (d:Document) + WHERE d.fileName IN [{placeholders}] + RETURN d.fileName as fileName, d.url as url, d.fileSource as fileSource + """ + + url_results = execute_graph_query(graph, url_query) + + # Create mapping of fileName to URL + url_mapping = {} + for result in url_results: + if result.get('url'): + url_mapping[result['fileName']] = { + 'url': result['url'], + 'fileSource': result.get('fileSource', '') + } + + # Enhance chunks with URLs + enhanced_chunks = [] + for chunk in chunks: + enhanced_chunk = chunk.copy() + + # Try to find URL for this chunk + chunk_url = None + + # 1. Check if chunk already has a URL + if chunk.get('source', '').startswith('http'): + chunk_url = chunk['source'] + + # 2. Try to get URL from document name + elif chunk.get('document_name') and chunk['document_name'] in url_mapping: + chunk_url = url_mapping[chunk['document_name']]['url'] + + # 3. Try to extract fileName from source and look up URL + elif chunk.get('source', '').startswith('Document: '): + doc_name = chunk['source'].replace('Document: ', '') + if doc_name in url_mapping: + chunk_url = url_mapping[doc_name]['url'] + + # Update chunk source with URL if found + if chunk_url: + enhanced_chunk['source'] = chunk_url + logging.info(f"Enhanced chunk with URL: {chunk_url}") + else: + logging.info(f"Could not find URL for chunk: {chunk.get('source', 'Unknown')}") + + enhanced_chunks.append(enhanced_chunk) + + graph.close() + return enhanced_chunks + + graph.close() + return chunks + + except Exception as e: + logging.error(f"Error enhancing chunks with URLs: {str(e)}") + return chunks + +def extract_subgraph_info(subgraph_data: Dict[str, Any]) -> Dict[str, Any]: + """ + Extract summary information about the subgraph. + + Args: + subgraph_data: Subgraph data from search_and_get_subgraph + + Returns: + Dictionary with subgraph summary information + """ + try: + total_nodes = 0 + total_relationships = 0 + entity_connections = 0 + + for subgraph in subgraph_data.get('subgraphs', []): + total_nodes += len(subgraph.get('nodes', [])) + total_relationships += len(subgraph.get('relationships', [])) + + # Count entity connections + for rel in subgraph.get('relationships', []): + if rel.get('type') in ['MENTIONED_IN', 'RELATED_TO', 'WORKS_FOR', 'FOUNDED', 'INVESTED_IN']: + entity_connections += 1 + + return { + 'total_nodes': total_nodes, + 'total_relationships': total_relationships, + 'entity_connections': entity_connections + } + + except Exception as e: + logging.error(f"Error extracting subgraph info: {str(e)}") + return { + 'total_nodes': 0, + 'total_relationships': 0, + 'entity_connections': 0 + } + +def assess_risk_with_llm(entity_name: str, entity_type: str, risk_indicators: Dict[str, int], + chunks: List[Dict[str, Any]], subgraph_info: Dict[str, Any]) -> Dict[str, Any]: + """ + Use LLM to assess risk based on extracted chunks and graph context. + + Args: + entity_name: Name of the entity to assess + entity_type: Type of entity (individual or organization) + risk_indicators: Dictionary of risk indicators and their weights + chunks: List of relevant document chunks + subgraph_info: Summary information about the subgraph + + Returns: + Risk assessment result as dictionary + """ + try: + # Load LLM + llm_model = os.getenv('RISK_ASSESSMENT_MODEL', 'openai_gpt_4o') + llm, _ = get_llm(llm_model) + + # Prepare template context + template_context = { + 'entity_name': entity_name, + 'entity_type': entity_type, + 'risk_indicators': risk_indicators, + 'chunks': chunks, + 'subgraph_info': subgraph_info + } + + # Render prompt template + template = Template(RISK_ASSESSMENT_PROMPT) + prompt = template.render(**template_context) + + logging.info(f"Generating risk assessment for entity: {entity_name}") + + # Get LLM response + response = llm.invoke(prompt) + response_text = response.content if hasattr(response, 'content') else str(response) + + # Extract JSON from response + try: + # Find JSON in the response (in case there's extra text) + start_idx = response_text.find('{') + end_idx = response_text.rfind('}') + 1 + + if start_idx != -1 and end_idx != 0: + json_str = response_text[start_idx:end_idx] + risk_assessment = json.loads(json_str) + + # Validate required fields + required_fields = ['entityName', 'entityType', 'riskAssessments', 'calculation', 'finalAssessment'] + for field in required_fields: + if field not in risk_assessment: + raise ValueError(f"Missing required field: {field}") + + return risk_assessment + else: + raise ValueError("No JSON found in response") + + except json.JSONDecodeError as e: + logging.error(f"Failed to parse JSON from LLM response: {str(e)}") + logging.error(f"Response text: {response_text}") + raise ValueError(f"Invalid JSON response from LLM: {str(e)}") + + except Exception as e: + logging.error(f"Error in risk assessment with LLM: {str(e)}") + raise Exception(f"Failed to assess risk: {str(e)}") + +def analyze_risk(uri: str, username: str, password: str, database: str, + entity_name: str, entity_type: str, risk_indicators: Dict[str, int], + depth: int = 4, max_results: int = 10) -> Dict[str, Any]: + """ + Main function to analyze risk for an entity. + + Args: + uri: Neo4j database URI + username: Database username + password: Database password + database: Database name + entity_name: Name of the entity to assess + entity_type: Type of entity (individual or organization) + risk_indicators: Dictionary of risk indicators and their weights + depth: Depth for subgraph extraction + max_results: Maximum number of search results to consider + + Returns: + Complete risk assessment result + """ + try: + logging.info(f"Starting risk analysis for entity: {entity_name} ({entity_type})") + + # Step 1: Search for entity and extract subgraph (same as search_nodes) + subgraph_data = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term=entity_name, + node_type=entity_type, + depth=depth, + max_results=max_results, + extract_best_match_only=True, # Only extract from best match for efficiency + preserve_text=True # Preserve text content for chunk extraction + ) + + if not subgraph_data.get('subgraphs'): + logging.warning(f"No subgraph found for entity: {entity_name}") + return { + "error": "Entity not found in database", + "entityName": entity_name, + "entityType": entity_type + } + + # Step 2: Extract relevant chunks from subgraph + chunks = extract_chunks_from_subgraph(subgraph_data) + logging.info(f"Extracted {len(chunks)} relevant chunks for risk assessment") + + # Step 2.5: Enhance chunks with URLs from database + chunks = enhance_chunks_with_urls(uri, username, password, database, chunks) + logging.info(f"Enhanced {len(chunks)} chunks with URL information") + + # Step 3: Extract subgraph summary information + subgraph_info = extract_subgraph_info(subgraph_data) + logging.info(f"Subgraph info: {subgraph_info}") + + # Step 4: Use LLM to assess risk based on chunks and context + risk_assessment = assess_risk_with_llm( + entity_name=entity_name, + entity_type=entity_type, + risk_indicators=risk_indicators, + chunks=chunks, + subgraph_info=subgraph_info + ) + + # Step 5: Add metadata about the analysis + risk_assessment['analysis_metadata'] = { + 'chunks_analyzed': len(chunks), + 'subgraph_nodes': subgraph_info['total_nodes'], + 'subgraph_relationships': subgraph_info['total_relationships'], + 'search_method': subgraph_data.get('best_match', {}).get('search_method', 'unknown'), + 'best_match_score': subgraph_data.get('best_match', {}).get('score', 'N/A') + } + + logging.info(f"Risk analysis completed for entity: {entity_name}") + return risk_assessment + + except Exception as e: + logging.error(f"Error in risk analysis: {str(e)}") + raise Exception(f"Risk analysis failed: {str(e)}") diff --git a/backend/src/risk_monitor.py b/backend/src/risk_monitor.py new file mode 100644 index 000000000..4091655a6 --- /dev/null +++ b/backend/src/risk_monitor.py @@ -0,0 +1,484 @@ +""" +Risk Monitoring Module +Provides functionality to monitor documents for specific names and risk indicators +""" + +import json +import logging +from datetime import datetime +from typing import List, Dict, Any, Optional +from .constants.risk_monitoring_prompts import RISK_MONITORING_PROMPTS, RISK_LEVELS + + +def validate_document_exists(graph, document_name: str) -> Optional[Dict[str, Any]]: + """Check if document exists and return basic info.""" + try: + # First, let's check what documents exist and their exact names + debug_query = """ + MATCH (d:Document) + RETURN d.fileName AS filename, d.id AS id, d.size AS size, d.created_date AS created_date + LIMIT 10 + """ + debug_result = graph.query(debug_query, {}) + logging.info(f"Available documents: {debug_result}") + + # Now check for the specific document + query = """ + MATCH (d:Document) + WHERE d.fileName = $document_name + OPTIONAL MATCH (c:Chunk)-[:PART_OF]->(d) + WITH d, count(c) AS chunk_count + RETURN { + exists: true, + document_id: d.id, + size: d.size, + chunk_count: chunk_count, + created_date: d.created_date + } AS info + """ + + result = graph.query(query, {"document_name": document_name}) + if result: + logging.info(f"Document found: {result[0]}") + return result[0] + else: + logging.warning(f"Document '{document_name}' not found in database") + return None + except Exception as e: + logging.error(f"Error validating document existence: {str(e)}") + return None + + +def extract_document_chunks(graph, document_name: str) -> List[Dict[str, Any]]: + """Extract all chunks from a document.""" + try: + # First, let's check if the document exists and has chunks + debug_query = """ + MATCH (d:Document {fileName: $document_name}) + OPTIONAL MATCH (c:Chunk)-[:PART_OF]->(d) + RETURN d.fileName AS doc_name, count(c) AS chunk_count + """ + debug_result = graph.query(debug_query, {"document_name": document_name}) + logging.info(f"Document chunk check: {debug_result}") + + # Now get the actual chunks + query = """ + MATCH (c:Chunk)-[:PART_OF]->(d:Document) + WHERE d.fileName = $document_name + RETURN { + id: c.id, + text: c.text, + position: c.position, + metadata: c.metadata + } AS chunk + ORDER BY c.position + """ + + result = graph.query(query, {"document_name": document_name}) + logging.info(f"Found {len(result)} chunks for document '{document_name}'") + + if not result: + logging.warning(f"No chunks found for document '{document_name}'. This usually means the document was uploaded but never processed.") + + # Extract the chunk data from the query result + chunks = [] + for row in result: + chunk_data = row.get('chunk', {}) + if chunk_data: + chunks.append(dict(chunk_data)) + + return chunks + except Exception as e: + logging.error(f"Error extracting document chunks: {str(e)}") + return [] + + +def call_llm_for_analysis(prompt: str, model: str) -> Optional[str]: + """Call LLM for analysis with error handling.""" + try: + # Import here to avoid circular imports + from .llm import get_llm + + # Use the proper LLM configuration system + llm, model_name = get_llm(model) + + response = llm.invoke(prompt) + return response.content + except Exception as e: + logging.error(f"LLM call failed: {str(e)}") + return None + + +def create_fallback_name_results(llm_response: str, monitored_names: List[str]) -> Dict[str, Any]: + """Create fallback results if LLM response parsing fails.""" + # Return empty results to avoid false positives + # The LLM should provide proper JSON responses, not fallback to text matching + return { + "names_found": [], + "occurrences": [], + "context": {}, + "risk_indicators": {} + } + + +def create_fallback_risk_results(llm_response: str, risk_indicators: List[str]) -> Dict[str, Any]: + """Create fallback results if LLM response parsing fails.""" + # Return empty results to avoid false positives + # The LLM should provide proper JSON responses, not fallback to text matching + return { + "indicators_found": [], + "risk_scores": {}, + "evidence": {}, + "severity_assessment": {} + } + + +def parse_name_monitoring_response(llm_response: str, monitored_names: List[str]) -> Dict[str, Any]: + """Parse LLM response for name monitoring.""" + try: + # Clean the response - remove markdown code blocks if present + cleaned_response = llm_response.strip() + if cleaned_response.startswith('```json'): + cleaned_response = cleaned_response[7:] # Remove ```json + if cleaned_response.endswith('```'): + cleaned_response = cleaned_response[:-3] # Remove ``` + cleaned_response = cleaned_response.strip() + + parsed = json.loads(cleaned_response) + return parsed + except json.JSONDecodeError: + logging.warning("Failed to parse LLM response as JSON, using fallback parsing") + return create_fallback_name_results(llm_response, monitored_names) + + +def parse_risk_analysis_response(llm_response: str, risk_indicators: List[str]) -> Dict[str, Any]: + """Parse LLM response for risk analysis.""" + try: + # Clean the response - remove markdown code blocks if present + cleaned_response = llm_response.strip() + if cleaned_response.startswith('```json'): + cleaned_response = cleaned_response[7:] # Remove ```json + if cleaned_response.endswith('```'): + cleaned_response = cleaned_response[:-3] # Remove ``` + cleaned_response = cleaned_response.strip() + + parsed = json.loads(cleaned_response) + return parsed + except json.JSONDecodeError: + logging.warning("Failed to parse LLM response as JSON, using fallback parsing") + return create_fallback_risk_results(llm_response, risk_indicators) + + +def monitor_names_in_document(document_chunks: List[Dict[str, Any]], monitored_names: List[str], model: str) -> Dict[str, Any]: + """Monitor document for specific names and their context.""" + + # Create LLM prompt for name monitoring + document_content = "\n\n".join([f"Chunk {i+1}: {chunk['text']}" for i, chunk in enumerate(document_chunks)]) + + # Debug logging + logging.info(f"Document content length: {len(document_content)}") + logging.info(f"Document content preview: {document_content[:500]}...") + logging.info(f"Monitored names: {monitored_names}") + + name_monitoring_prompt = RISK_MONITORING_PROMPTS["NAME_MONITORING"].format( + monitored_names=", ".join(monitored_names), + document_content=document_content + ) + + # Use LLM to analyze names + llm_response = call_llm_for_analysis(name_monitoring_prompt, model) + + # Debug logging + logging.info(f"Name monitoring LLM response: {llm_response}") + + if not llm_response: + # Fallback to simple text search + return create_fallback_name_results("", monitored_names) + + # Parse LLM response + name_results = parse_name_monitoring_response(llm_response, monitored_names) + + return { + "names_found": name_results.get("names_found", []), + "name_occurrences": name_results.get("occurrences", []), + "context_analysis": name_results.get("context", {}), + "risk_indicators_per_name": name_results.get("risk_indicators", {}) + } + + +def analyze_risk_indicators(document_chunks: List[Dict[str, Any]], risk_indicators: List[str], model: str) -> Dict[str, Any]: + """Analyze document for risk indicators.""" + + # Create LLM prompt for risk analysis + document_content = "\n\n".join([f"Chunk {i+1}: {chunk['text']}" for i, chunk in enumerate(document_chunks)]) + + risk_analysis_prompt = RISK_MONITORING_PROMPTS["RISK_ANALYSIS"].format( + risk_indicators=", ".join(risk_indicators), + document_content=document_content + ) + + # Use LLM to analyze risk indicators + llm_response = call_llm_for_analysis(risk_analysis_prompt, model) + + # Debug logging + logging.info(f"Risk analysis LLM response: {llm_response}") + + if not llm_response: + # Fallback to simple text search + return create_fallback_risk_results("", risk_indicators) + + # Parse LLM response + risk_results = parse_risk_analysis_response(llm_response, risk_indicators) + + return { + "indicators_found": risk_results.get("indicators_found", []), + "risk_scores": risk_results.get("risk_scores", {}), + "evidence": risk_results.get("evidence", {}), + "severity_assessment": risk_results.get("severity", {}) + } + + +def calculate_name_risk_score(name_monitoring_results: Dict[str, Any]) -> float: + """Calculate overall risk score from name monitoring.""" + if not name_monitoring_results.get("names_found"): + return 0.0 + + total_score = 0.0 + count = 0 + + for name_result in name_monitoring_results["names_found"]: + if "overall_risk_score" in name_result: + total_score += name_result["overall_risk_score"] + count += 1 + + return total_score / count if count > 0 else 0.0 + + +def calculate_indicator_risk_score(risk_analysis_results: Dict[str, Any]) -> float: + """Calculate overall risk score from risk indicator analysis.""" + if not risk_analysis_results.get("indicators_found"): + return 0.0 + + total_score = 0.0 + count = 0 + + for indicator_result in risk_analysis_results["indicators_found"]: + if "risk_score" in indicator_result: + total_score += indicator_result["risk_score"] + count += 1 + + return total_score / count if count > 0 else 0.0 + + +def get_risk_level(risk_score: float) -> str: + """Get risk level based on score.""" + for level, config in RISK_LEVELS.items(): + if config["min"] <= risk_score <= config["max"]: + return level + return "UNKNOWN" + + +def generate_risk_assessment(name_monitoring_results: Dict[str, Any], risk_analysis_results: Dict[str, Any], risk_threshold: float) -> Dict[str, Any]: + """Generate overall risk assessment and alerts.""" + + # Calculate overall risk score + name_risk_score = calculate_name_risk_score(name_monitoring_results) + indicator_risk_score = calculate_indicator_risk_score(risk_analysis_results) + + overall_risk_score = (name_risk_score + indicator_risk_score) / 2 + + # Generate alerts + alerts = [] + if overall_risk_score >= risk_threshold: + alerts.append({ + "type": "HIGH_RISK", + "score": overall_risk_score, + "description": f"Overall risk score {overall_risk_score:.2f} exceeds threshold {risk_threshold}", + "timestamp": datetime.now().isoformat() + }) + + # Add specific alerts for high-risk names + for name_result in name_monitoring_results.get("names_found", []): + if name_result.get("overall_risk_score", 0) >= risk_threshold: + alerts.append({ + "type": "NAME_RISK", + "name": name_result["name"], + "score": name_result["overall_risk_score"], + "description": f"High risk associated with name: {name_result['name']}", + "context": name_result.get("context", ""), + "timestamp": datetime.now().isoformat() + }) + + # Add specific alerts for high-risk indicators + for indicator_result in risk_analysis_results.get("indicators_found", []): + if indicator_result.get("risk_score", 0) >= risk_threshold: + alerts.append({ + "type": "INDICATOR_RISK", + "indicator": indicator_result["indicator"], + "score": indicator_result["risk_score"], + "description": f"High risk indicator found: {indicator_result['indicator']}", + "evidence": indicator_result.get("evidence", ""), + "timestamp": datetime.now().isoformat() + }) + + return { + "overall_risk_score": overall_risk_score, + "name_risk_score": name_risk_score, + "indicator_risk_score": indicator_risk_score, + "alert_required": overall_risk_score >= risk_threshold, + "alerts": alerts, + "risk_level": get_risk_level(overall_risk_score) + } + + +def generate_entity_risk_alerts(document_chunks: List[Dict[str, Any]], monitored_names: List[str], risk_indicators: List[str], risk_threshold: float, model: str) -> List[Dict[str, Any]]: + """Generate alerts for entities with risk indicators found in document.""" + + # Create comprehensive LLM prompt for entity risk alerts + document_content = "\n\n".join([f"Chunk {i+1}: {chunk['text']}" for i, chunk in enumerate(document_chunks)]) + + entity_risk_prompt = RISK_MONITORING_PROMPTS["ENTITY_RISK_ALERTS"].format( + monitored_names=", ".join(monitored_names), + risk_indicators=", ".join(risk_indicators), + risk_threshold=risk_threshold, + document_content=document_content + ) + + # Use LLM to generate entity-based alerts + llm_response = call_llm_for_analysis(entity_risk_prompt, model) + + # Debug logging + logging.info(f"Entity risk alerts LLM response: {llm_response}") + logging.info(f"Document chunks count: {len(document_chunks)}") + logging.info(f"Monitored names: {monitored_names}") + logging.info(f"Risk indicators: {risk_indicators}") + + if not llm_response: + logging.warning("No LLM response received") + return [] + + # Parse LLM response + try: + cleaned_response = llm_response.strip() + + # Handle markdown code blocks + if cleaned_response.startswith('```json'): + cleaned_response = cleaned_response[7:] + if cleaned_response.startswith('```'): + cleaned_response = cleaned_response[3:] + + # Find the end of the JSON block (before any explanation) + json_end = cleaned_response.find('```') + if json_end != -1: + cleaned_response = cleaned_response[:json_end] + + # Also look for explanation markers + explanation_markers = ['### Explanation:', '## Explanation:', '# Explanation:', 'Explanation:'] + for marker in explanation_markers: + explanation_start = cleaned_response.find(marker) + if explanation_start != -1: + cleaned_response = cleaned_response[:explanation_start] + + cleaned_response = cleaned_response.strip() + + parsed = json.loads(cleaned_response) + alerts = parsed.get("alerts", []) + + # Format alerts for frontend + formatted_alerts = [] + for i, alert in enumerate(alerts): + formatted_alerts.append({ + "id": f"alert_{i + 1}", + "title": alert.get("title", f"Risk Alert for {alert.get('entity_name', 'Unknown')}"), + "description": alert.get("description", ""), + "timestamp": datetime.now().isoformat(), + "risk_score": alert.get("risk_score", 0.0), + "is_active": True, + "entity_name": alert.get("entity_name", "Unknown"), + "evidence": alert.get("evidence", ""), + "risk_indicator": alert.get("risk_indicator", "") + }) + + return formatted_alerts + + except json.JSONDecodeError: + logging.warning("Failed to parse entity risk alerts LLM response as JSON") + return [] + + +def perform_risk_monitoring( + graph, + document_name: str, + monitored_names: List[str], + risk_indicators: List[str], + risk_threshold: float = 0.7, + model: str = "gpt-4", + mode: str = None +) -> Dict[str, Any]: + """ + Monitor a document for specific names and risk indicators. + + Args: + graph: Database connection + document_name: Name of the document to monitor + monitored_names: List of names to monitor + risk_indicators: List of risk indicators to check + risk_threshold: Risk score threshold for alerts + model: LLM model to use + mode: Processing mode + write_access: User write permissions + + Returns: + dict: Risk monitoring results with alerts and analysis + """ + try: + # 1. Validate document exists + document_info = validate_document_exists(graph, document_name) + if not document_info: + return { + "success": False, + "error": f"Document '{document_name}' not found", + "info": {"document_name": document_name} + } + + # 2. Extract document content and chunks + document_chunks = extract_document_chunks(graph, document_name) + if not document_chunks: + return { + "success": False, + "error": f"No content found in document '{document_name}'", + "info": {"document_name": document_name} + } + + # 3. Generate entity-based risk alerts + alerts = generate_entity_risk_alerts( + document_chunks, + monitored_names, + risk_indicators, + risk_threshold, + model + ) + + # 4. Format results for frontend (matching MonitoringResult interface) + formatted_results = { + "success": True, + "document_name": document_name, + "alerts": alerts, + "debug_info": { + "chunks_analyzed": len(document_chunks), + "monitored_names": monitored_names, + "risk_indicators": risk_indicators, + "alerts_generated": len(alerts) + } + } + + return formatted_results + + except Exception as e: + logging.error(f"Error in perform_risk_monitoring: {str(e)}") + return { + "success": False, + "error": str(e), + "document_name": document_name, + "alerts": [] + } diff --git a/backend/src/shared/constants.py b/backend/src/shared/constants.py index 30cedfdfd..ea551519f 100644 --- a/backend/src/shared/constants.py +++ b/backend/src/shared/constants.py @@ -892,6 +892,108 @@ types such as dates, numbers, revenues, and other non-entity information are not extracted as separate nodes. Instead, treat these as properties associated with the relevant entities.""" +RISK_ASSESSMENT_PROMPT = """ +You are an expert Canadian research security risk assessor. +Assess the research-security risk of the following entity and return only a valid JSON object. + +Entity: {{ entity_name }} ({{ entity_type }}) + +Risk Indicators & Weights (1โ€“100 each): +{% for indicator, weight in risk_indicators.items() %} +{{ indicator }}: {{ weight }} +{% endfor %} + +Context Information: +The following information was extracted from the knowledge graph about this entity: + +{% if chunks %} +Relevant Document Chunks: +{% for chunk in chunks %} +Chunk {{ loop.index }}: +Text: {{ chunk.text }} +Source: {{ chunk.source if chunk.source else "Unknown" }} +Document: {{ chunk.document_name or chunk.document_id or "Unknown" }} +{% endfor %} + +Source Reference Instructions: +- Use the exact source URL if available (e.g., "https://example.com/article") +- Use document names if no URL (e.g., "Document: Apple stock during pandemic.pdf") +- Use chunk references if no specific source (e.g., "Chunk 1", "Chunk 3") +- Use "nil" only when no evidence exists for an indicator + +CRITICAL: When citing sources, ALWAYS use the "Source:" field from the chunk above, NOT "Chunk X" references. +If a chunk shows "Source: Document: Bill_Gates", cite it as "Document: Bill_Gates", not "Chunk 1". +{% else %} +No relevant document chunks found for this entity. +{% endif %} + +{% if subgraph_info %} +Graph Context: +- Total related nodes: {{ subgraph_info.total_nodes }} +- Total relationships: {{ subgraph_info.total_relationships }} +- Entity connections: {{ subgraph_info.entity_connections }} +{% endif %} + +Scoring Guidance: +For each indicator, assign a score from 1โ€“5 (1 = very low risk, 5 = very high risk). +Provide a short, evidence-based explanation and at least one citation (URL or identifiable source) per indicator. +Use the actual source URLs from the chunks when available. If no specific evidence is found for an indicator, use "nil" as the source and score conservatively. + +Weights reflect indicator importance (1โ€“100). All weights are combined and normalized during calculation. + +Final Score Calculation (deterministic): +Let totalWeight = sum(weights). +For each indicator, normalizedWeight = weight / totalWeight. +overallScore = sum(score_i * normalizedWeight_i) (range 1โ€“5). + +Traffic light mapping (use these exact thresholds): +Red if overallScore >= 4.0 +Yellow if 2.5 <= overallScore < 4.0 +Blue if overallScore < 2.5 + +Required JSON format (no extra keys, no commentary outside JSON): +{ + "entityName": "", + "entityType": "", + "riskAssessments": [ + { + "indicator": "", + "weight": <1-100>, + "score": <1-5>, + "explanation": "", + "sources": ["", ""], + "normalizedWeight": <0-1>, + "weightedContribution": + } + ], + "calculation": { + "totalWeight": , + "overallScore": , + "thresholdsApplied": { + "red": "overallScore >= 4.0", + "yellow": "2.5 <= overallScore < 4.0", + "blue": "overallScore < 2.5" + } + }, + "finalAssessment": { + "trafficLight": "", + "overallExplanation": "" + } +} + +IMPORTANT: Do not hallucinate. Only use evidence from the provided chunks and graph context. + +For sources, use the following priority: +1. If a chunk has a valid URL in its source field, use that URL +2. If a chunk has a document name but no URL, use "Document: [document_name]" +3. If no specific source is available, use "Chunk [number]" as reference +4. If no evidence exists for an indicator, use "nil" as the source + +CRITICAL: Always use the exact "Source:" value from the chunk data above. Do NOT create "Chunk X" references. + +Provide a conservative score with explanation that no evidence was found when appropriate. +""" + SCHEMA_VISUALIZATION_QUERY = """ CALL db.schema.visualization() YIELD nodes, relationships RETURN diff --git a/backend/src/subgraph_monitor.py b/backend/src/subgraph_monitor.py new file mode 100644 index 000000000..b1a54141e --- /dev/null +++ b/backend/src/subgraph_monitor.py @@ -0,0 +1,422 @@ +""" +Subgraph Monitoring Service for automatic risk detection +""" + +import hashlib +import logging +from datetime import datetime +from typing import Dict, List, Any, Optional, Tuple +from src.database import DatabaseManager +from src.shared.common_fn import create_graph_database_connection + +logger = logging.getLogger(__name__) + +class SubgraphMonitor: + def __init__(self): + self.db = DatabaseManager() + self.logger = logger + + def extract_entity_subgraph(self, entity_name: str, graph_connection) -> Dict[str, Any]: + """ + Extract subgraph for a specific entity using Cypher query + """ + try: + # First, try to find the entity with different possible labels and properties + queries = [ + # Try __Entity__ label with id property (exact match) + { + "query": """ + MATCH (e:__Entity__ {id: $entity_name}) + OPTIONAL MATCH (e)-[r]-(related) + WITH e, collect(DISTINCT related) as nodes, collect(DISTINCT r) as relationships + RETURN + size(nodes) as node_count, + size(relationships) as relationship_count, + e.id as entity_id, + e.description as entity_description + """, + "params": {"entity_name": entity_name} + }, + # Try __Entity__ label with name property (exact match) + { + "query": """ + MATCH (e:__Entity__ {name: $entity_name}) + OPTIONAL MATCH (e)-[r]-(related) + WITH e, collect(DISTINCT related) as nodes, collect(DISTINCT r) as relationships + RETURN + size(nodes) as node_count, + size(relationships) as relationship_count, + e.id as entity_id, + e.description as entity_description + """, + "params": {"entity_name": entity_name} + }, + # Try __Entity__ label with partial name match + { + "query": """ + MATCH (e:__Entity__) + WHERE e.id CONTAINS $entity_name OR e.name CONTAINS $entity_name OR e.description CONTAINS $entity_name + OPTIONAL MATCH (e)-[r]-(related) + WITH e, collect(DISTINCT related) as nodes, collect(DISTINCT r) as relationships + RETURN + size(nodes) as node_count, + size(relationships) as relationship_count, + e.id as entity_id, + e.description as entity_description + LIMIT 1 + """, + "params": {"entity_name": entity_name} + }, + # Try Entity label (without underscores) with various properties + { + "query": """ + MATCH (e:Entity) + WHERE e.id = $entity_name OR e.name = $entity_name OR e.description CONTAINS $entity_name + OPTIONAL MATCH (e)-[r]-(related) + WITH e, collect(DISTINCT related) as nodes, collect(DISTINCT r) as relationships + RETURN + size(nodes) as node_count, + size(relationships) as relationship_count, + e.id as entity_id, + e.description as entity_description + LIMIT 1 + """, + "params": {"entity_name": entity_name} + }, + # Try searching by any label with any property containing the name + { + "query": """ + MATCH (e) + WHERE e.id CONTAINS $entity_name OR e.name CONTAINS $entity_name OR e.description CONTAINS $entity_name + OPTIONAL MATCH (e)-[r]-(related) + WITH e, collect(DISTINCT related) as nodes, collect(DISTINCT r) as relationships + RETURN + size(nodes) as node_count, + size(relationships) as relationship_count, + e.id as entity_id, + e.description as entity_description + LIMIT 1 + """, + "params": {"entity_name": entity_name} + } + ] + + for i, query_info in enumerate(queries): + try: + self.logger.info(f"Trying query {i+1} for entity: {entity_name}") + self.logger.debug(f"Query: {query_info['query']}") + self.logger.debug(f"Params: {query_info['params']}") + + result = graph_connection.query(query_info["query"], query_info["params"]) + + if result and len(result) > 0: + record = result[0] + subgraph_data = { + "entity_name": entity_name, + "node_count": record["node_count"], + "relationship_count": record["relationship_count"], + "entity_id": record["entity_id"], + "entity_description": record["entity_description"], + "timestamp": datetime.now() + } + + # Generate subgraph signature for change detection + signature_data = f"{entity_name}:{record['node_count']}:{record['relationship_count']}" + subgraph_data["subgraph_signature"] = hashlib.md5(signature_data.encode()).hexdigest() + + self.logger.info(f"Extracted subgraph for {entity_name} using query {i+1}: {record['node_count']} nodes, {record['relationship_count']} relationships") + return subgraph_data + else: + self.logger.debug(f"Query {i+1} returned no results for {entity_name}") + + except Exception as e: + self.logger.debug(f"Query {i+1} failed for {entity_name}: {str(e)}") + continue + + # If all queries failed, log a warning + self.logger.warning(f"No subgraph found for entity: {entity_name} after trying all query variations") + return None + + except Exception as e: + self.logger.error(f"Error extracting subgraph for {entity_name}: {str(e)}") + return None + + def get_monitored_entities(self) -> List[Dict[str, Any]]: + """ + Get all monitored entities from database + """ + try: + query = """ + SELECT id, name, type, risk_threshold, category, status, + last_subgraph_nodes, last_subgraph_relationships, + last_subgraph_timestamp, subgraph_signature + FROM monitored_entities + WHERE status = 'active' + ORDER BY name + """ + + result = self.db.execute_query(query) + return [dict(row) for row in result] + + except Exception as e: + self.logger.error(f"Error getting monitored entities: {str(e)}") + return [] + + def update_entity_subgraph(self, entity_id: int, subgraph_data: Dict[str, Any]) -> bool: + """ + Update entity's subgraph information in database + """ + try: + query = """ + UPDATE monitored_entities + SET last_subgraph_nodes = %s, + last_subgraph_relationships = %s, + last_subgraph_timestamp = %s, + subgraph_signature = %s, + updated_at = %s + WHERE id = %s + """ + + params = ( + subgraph_data["node_count"], + subgraph_data["relationship_count"], + subgraph_data["timestamp"], + subgraph_data["subgraph_signature"], + datetime.now(), + entity_id + ) + + self.db.execute_query(query, params) + self.logger.info(f"Updated subgraph for entity {entity_id}") + return True + + except Exception as e: + self.logger.error(f"Error updating subgraph for entity {entity_id}: {str(e)}") + return False + + def store_subgraph_snapshot(self, entity_id: int, subgraph_data: Dict[str, Any]) -> bool: + """ + Store a snapshot of the subgraph for historical tracking + """ + try: + query = """ + INSERT INTO subgraph_snapshots (entity_id, node_count, relationship_count, + subgraph_signature, timestamp) + VALUES (%s, %s, %s, %s, %s) + """ + + params = ( + entity_id, + subgraph_data["node_count"], + subgraph_data["relationship_count"], + subgraph_data["subgraph_signature"], + subgraph_data["timestamp"] + ) + + self.db.execute_query(query, params) + return True + + except Exception as e: + self.logger.error(f"Error storing subgraph snapshot: {str(e)}") + return False + + def has_subgraph_changed(self, entity: Dict[str, Any], current_subgraph: Dict[str, Any]) -> Tuple[bool, Dict[str, Any]]: + """ + Check if entity's subgraph has changed significantly + """ + try: + if not entity.get("subgraph_signature"): + # First time monitoring this entity + return True, {"type": "initial_monitoring", "details": "First subgraph snapshot"} + + # Check if signature changed + if entity["subgraph_signature"] != current_subgraph["subgraph_signature"]: + change_details = { + "type": "subgraph_change", + "details": (f"Subgraph signature changed. " + f"Nodes: {entity['last_subgraph_nodes']} โ†’ {current_subgraph['node_count']} " + f"Relationships: {entity['last_subgraph_relationships']} โ†’ {current_subgraph['relationship_count']}") + } + + # Check if change is significant (more than 10% change) + if entity.get("last_subgraph_nodes") and entity.get("last_subgraph_relationships"): + node_change = abs(current_subgraph["node_count"] - entity["last_subgraph_nodes"]) + rel_change = abs(current_subgraph["relationship_count"] - entity["last_subgraph_relationships"]) + + if node_change > entity["last_subgraph_nodes"] * 0.1 or rel_change > entity["last_subgraph_relationships"] * 0.1: + change_details["significance"] = "high" + change_details["details"] += " (Significant change detected)" + else: + change_details["significance"] = "low" + + return True, change_details + + return False, {} + + except Exception as e: + self.logger.error(f"Error checking subgraph changes: {str(e)}") + return False, {} + + async def _trigger_risk_assessment(self, entity: Dict[str, Any], current_subgraph: Dict[str, Any], + graph_connection, model: str = "openai_gpt_4o") -> Dict[str, Any]: + """ + Trigger risk assessment when subgraph changes are detected + """ + try: + from src.monitoring_service_pg import MonitoringServicePG + + monitoring_service = MonitoringServicePG() + + # Get current risk assessment + current_risk = await monitoring_service._get_entity_subgraph(graph_connection, entity["name"]) + + # Get previous risk assessment + previous_assessment = monitoring_service.get_latest_risk_assessment(entity["id"]) + + # Analyze risk changes + risk_analysis = await monitoring_service._analyze_entity_risk_changes( + entity, current_risk, previous_assessment, model + ) + + # Store new risk assessment + if risk_analysis["current_risk_score"] is not None: + assessment_data = { + "risk_score": risk_analysis["current_risk_score"], + "risk_level": risk_analysis["risk_level"], + "connections_count": risk_analysis["connections_count"], + "risk_indicators": risk_analysis["risk_indicators"] + } + monitoring_service.store_risk_assessment( + entity["id"], + assessment_data + ) + + # Generate alert if risk increased + if risk_analysis["risk_increased"]: + alert_message = await monitoring_service._generate_llm_alert( + entity, risk_analysis, current_risk, model + ) + + if alert_message: + alert_id = monitoring_service.create_alert( + entity["id"], + risk_analysis["alert_severity"], + alert_message + ) + self.logger.info(f"Generated alert {alert_id} for {entity['name']} due to subgraph changes") + + # Add alert info to risk analysis + risk_analysis["alert_id"] = alert_id + risk_analysis["alert_message"] = alert_message + + return risk_analysis + + except Exception as e: + self.logger.error(f"Error triggering risk assessment for {entity['name']}: {str(e)}") + return {"error": str(e), "risk_increased": False} + + async def monitor_all_entities(self, neo4j_uri: str = None, neo4j_username: str = None, + neo4j_password: str = None, neo4j_database: str = None, + model: str = "openai_gpt_4o") -> Dict[str, Any]: + """ + Monitor all active entities for subgraph changes and trigger risk assessment + """ + try: + self.logger.info("Starting enhanced subgraph monitoring with risk assessment for all entities") + + # Get monitored entities + entities = self.get_monitored_entities() + if not entities: + self.logger.info("No active monitored entities found") + return {"entities_checked": 0, "changes_detected": 0, "alerts_generated": 0, "results": []} + + # Establish Neo4j connection + graph_connection = None + if neo4j_uri and neo4j_username and neo4j_password: + try: + graph_connection = create_graph_database_connection( + neo4j_uri, neo4j_username, neo4j_password, neo4j_database + ) + self.logger.info("Neo4j connection established for enhanced subgraph monitoring") + except Exception as e: + self.logger.error(f"Failed to establish Neo4j connection: {e}") + return {"error": "Neo4j connection failed", "entities_checked": 0} + else: + self.logger.error("Neo4j connection parameters not provided") + return {"error": "Neo4j connection parameters required", "entities_checked": 0} + + results = [] + changes_detected = 0 + alerts_generated = 0 + + for entity in entities: + try: + # Extract current subgraph + current_subgraph = self.extract_entity_subgraph(entity["name"], graph_connection) + if not current_subgraph: + continue + + # Check for changes + has_changed, change_details = self.has_subgraph_changed(entity, current_subgraph) + + # Store subgraph snapshot + self.store_subgraph_snapshot(entity["id"], current_subgraph) + + # Update entity's current subgraph info + self.update_entity_subgraph(entity["id"], current_subgraph) + + # Trigger risk assessment if changes detected + risk_assessment = None + if has_changed: + self.logger.info(f"Subgraph changes detected for {entity['name']}, triggering risk assessment") + risk_assessment = await self._trigger_risk_assessment( + entity, current_subgraph, graph_connection, model + ) + + if risk_assessment and risk_assessment.get("risk_increased"): + alerts_generated += 1 + + # Prepare result + result = { + "entity_id": entity["id"], + "entity_name": entity["name"], + "has_changed": has_changed, + "change_details": change_details, + "current_subgraph": current_subgraph, + "previous_subgraph": { + "nodes": entity.get("last_subgraph_nodes", 0), + "relationships": entity.get("last_subgraph_relationships", 0), + "timestamp": entity.get("last_subgraph_timestamp") + }, + "risk_assessment": risk_assessment + } + + results.append(result) + + if has_changed: + changes_detected += 1 + self.logger.info(f"Change detected for {entity['name']}: {change_details}") + + except Exception as e: + self.logger.error(f"Error monitoring entity {entity['name']}: {str(e)}") + results.append({ + "entity_id": entity["id"], + "entity_name": entity["name"], + "error": str(e), + "has_changed": False + }) + + monitoring_result = { + "entities_checked": len(entities), + "changes_detected": changes_detected, + "alerts_generated": alerts_generated, + "timestamp": datetime.now().isoformat(), + "results": results + } + + self.logger.info(f"Enhanced subgraph monitoring completed: {changes_detected} changes detected, {alerts_generated} alerts generated out of {len(entities)} entities") + return monitoring_result + + except Exception as e: + self.logger.error(f"Error in enhanced subgraph monitoring: {str(e)}") + return {"error": str(e), "entities_checked": 0} diff --git a/backend/test_mcp_endpoint.py b/backend/test_mcp_endpoint.py new file mode 100644 index 000000000..946ea392d --- /dev/null +++ b/backend/test_mcp_endpoint.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +""" +Test script for the MCP API endpoint +""" + +import requests +import json +import time + +def test_mcp_endpoint(): + """Test the MCP chart generation endpoint""" + + # Test data + test_data = { + 'query': 'Show me all documents in the database', + 'chart_type': 'bar', + 'uri': 'neo4j+s://9379df68.databases.neo4j.io:7687', + 'userName': 'neo4j', + 'password': '_18dKuxBBytBxPuKZP5snPvXelfYs7uQKWcA_A9HUHU', # Replace with actual password + 'database': 'neo4j', + 'openai_api_key': 'your-openai-api-key-here', # Replace with actual API key + 'model': 'gpt-4' + } + + # Backend URL + backend_url = "http://localhost:8000/mcp/generate_chart" + + print("๐Ÿงช Testing MCP Chart Generation Endpoint") + print("=" * 50) + + try: + print(f"๐Ÿ“ก Sending request to: {backend_url}") + print(f"๐Ÿ“ Query: {test_data['query']}") + print(f"๐Ÿ“Š Chart Type: {test_data['chart_type']}") + + # Send POST request + response = requests.post(backend_url, data=test_data, timeout=60) + + print(f"๐Ÿ“ˆ Response Status: {response.status_code}") + + if response.status_code == 200: + result = response.json() + print("โœ… Request successful!") + print(f"๐Ÿ“‹ Response: {json.dumps(result, indent=2)}") + + if result.get('status') == 'Success': + print("๐ŸŽ‰ Chart generated successfully!") + if 'data' in result: + chart_data = result['data'] + print(f"๐Ÿ“Š Chart Type: {chart_data.get('metadata', {}).get('chart_type', 'Unknown')}") + print(f"โฑ๏ธ Processing Time: {chart_data.get('metadata', {}).get('processing_time', 'Unknown')}s") + print(f"๐Ÿ” Cypher Query: {chart_data.get('metadata', {}).get('cypher_query', 'Unknown')}") + else: + print(f"โŒ Chart generation failed: {result.get('message', 'Unknown error')}") + else: + print(f"โŒ Request failed with status {response.status_code}") + print(f"๐Ÿ“„ Response: {response.text}") + + except requests.exceptions.RequestException as e: + print(f"โŒ Network error: {e}") + except Exception as e: + print(f"โŒ Unexpected error: {e}") + +def test_stop_server(): + """Test the MCP server stop endpoint""" + + backend_url = "http://localhost:8000/mcp/stop_server" + + print("\n๐Ÿ›‘ Testing MCP Server Stop Endpoint") + print("=" * 50) + + try: + response = requests.post(backend_url, timeout=10) + print(f"๐Ÿ“ˆ Response Status: {response.status_code}") + + if response.status_code == 200: + result = response.json() + print("โœ… Request successful!") + print(f"๐Ÿ“‹ Response: {json.dumps(result, indent=2)}") + else: + print(f"โŒ Request failed with status {response.status_code}") + print(f"๐Ÿ“„ Response: {response.text}") + + except requests.exceptions.RequestException as e: + print(f"โŒ Network error: {e}") + except Exception as e: + print(f"โŒ Unexpected error: {e}") + +if __name__ == "__main__": + print("๐Ÿš€ MCP Endpoint Test Suite") + print("=" * 60) + + # Test chart generation + test_mcp_endpoint() + + # Wait a bit + time.sleep(2) + + # Test server stop + test_stop_server() + + print("\nโœ… Test suite completed!") diff --git a/backend/test_neo4j_entities.py b/backend/test_neo4j_entities.py new file mode 100644 index 000000000..816003bbe --- /dev/null +++ b/backend/test_neo4j_entities.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +""" +Test script to check Neo4j entities and subgraph extraction +""" + +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.shared.common_fn import create_graph_database_connection + +def test_neo4j_entities(): + """Test Neo4j connection and entity extraction""" + + print("๐Ÿ” Testing Neo4j Entity Extraction") + print("=" * 50) + + uri = "neo4j+ssc://224c5da6.databases.neo4j.io:7687" # From your logs + username = "neo4j" # From your logs + password = "your_password_here" # You need to provide this + database = "neo4j" # From your logs + + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + try: + # Test connection + print("\n1๏ธโƒฃ Testing Neo4j Connection...") + graph = create_graph_database_connection(uri, username, password, database) + print("โœ… Neo4j connection successful") + + # Test basic query + print("\n2๏ธโƒฃ Testing Basic Query...") + test_query = "MATCH (n) RETURN count(n) as total_nodes LIMIT 1" + result = graph.query(test_query) + print(f"Total nodes in database: {result[0]['total_nodes'] if result else 'Unknown'}") + + # Check what entity labels exist + print("\n3๏ธโƒฃ Checking Entity Labels...") + labels_query = "CALL db.labels() YIELD label RETURN label ORDER BY label" + labels_result = graph.query(labels_query) + print("Available labels:") + for row in labels_result: + print(f" - {row['label']}") + + # Check for entities with different possible labels + print("\n4๏ธโƒฃ Checking for Lori Greiner with different labels...") + + # Try __Entity__ label (from subgraph_monitor.py) + entity_query = """ + MATCH (e:__Entity__ {id: 'Lori Greiner'}) + RETURN e.id as id, e.description as description, labels(e) as labels + """ + entity_result = graph.query(entity_query) + if entity_result: + print("โœ… Found Lori Greiner with __Entity__ label:") + for row in entity_result: + print(f" - ID: {row['id']}, Description: {row['description']}, Labels: {row['labels']}") + else: + print("โŒ Lori Greiner not found with __Entity__ label") + + # Try Entity label (without underscores) + entity_query2 = """ + MATCH (e:Entity {id: 'Lori Greiner'}) + RETURN e.id as id, e.description as description, labels(e) as labels + """ + entity_result2 = graph.query(entity_query2) + if entity_result2: + print("โœ… Found Lori Greiner with Entity label:") + for row in entity_result2: + print(f" - ID: {row['id']}, Description: {row['description']}, Labels: {row['labels']}") + else: + print("โŒ Lori Greiner not found with Entity label") + + # Try searching by name property + name_query = """ + MATCH (e) + WHERE e.name = 'Lori Greiner' OR e.id = 'Lori Greiner' + RETURN e.id as id, e.name as name, e.description as description, labels(e) as labels + LIMIT 5 + """ + name_result = graph.query(name_query) + if name_result: + print("โœ… Found entities with name/id 'Lori Greiner':") + for row in name_result: + print(f" - ID: {row['id']}, Name: {row['name']}, Description: {row['description']}, Labels: {row['labels']}") + else: + print("โŒ No entities found with name/id 'Lori Greiner'") + + # Check what entities exist + print("\n5๏ธโƒฃ Checking What Entities Exist...") + entities_query = """ + MATCH (e) + WHERE e.id IS NOT NULL OR e.name IS NOT NULL + RETURN e.id as id, e.name as name, labels(e) as labels + LIMIT 10 + """ + entities_result = graph.query(entities_query) + print("Sample entities in database:") + for row in entities_result: + print(f" - ID: {row['id']}, Name: {row['name']}, Labels: {row['labels']}") + + # Test subgraph extraction query + print("\n6๏ธโƒฃ Testing Subgraph Extraction Query...") + if entity_result or entity_result2: + # Use the label that worked + working_label = "__Entity__" if entity_result else "Entity" + subgraph_query = f""" + MATCH (e:{working_label} {{id: 'Lori Greiner'}}) + OPTIONAL MATCH (e)-[r]-(related) + WITH e, collect(DISTINCT related) as nodes, collect(DISTINCT r) as relationships + RETURN + size(nodes) as node_count, + size(relationships) as relationship_count, + e.id as entity_id, + e.description as entity_description + """ + + subgraph_result = graph.query(subgraph_query) + if subgraph_result: + print("โœ… Subgraph extraction successful:") + for row in subgraph_result: + print(f" - Nodes: {row['node_count']}, Relationships: {row['relationship_count']}") + print(f" - Entity ID: {row['entity_id']}") + print(f" - Description: {row['entity_description']}") + else: + print("โŒ Subgraph extraction failed") + else: + print("โŒ Cannot test subgraph extraction - entity not found") + + except Exception as e: + print(f"\nโŒ Test failed with error: {str(e)}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + print("โš ๏ธ Note: You need to provide your actual Neo4j password in this script") + print(" Edit the script and replace 'your_password_here' with your actual password") + print() + + # Uncomment the line below and add your password to test + # test_neo4j_entities() + + print("To run this test:") + print("1. Edit this script and add your Neo4j password") + print("2. Uncomment the test_neo4j_entities() call") + print("3. Run: python3 test_neo4j_entities.py") diff --git a/backend/Performance_test.py b/backend/tests/Performance_test.py similarity index 100% rename from backend/Performance_test.py rename to backend/tests/Performance_test.py diff --git a/backend/tests/README.md b/backend/tests/README.md new file mode 100644 index 000000000..b89efd405 --- /dev/null +++ b/backend/tests/README.md @@ -0,0 +1,114 @@ +# Backend Tests + +This directory contains all test files for the LLM Graph Builder Backend. + +## Test Structure + +### Test Categories + +- **Unit Tests** (`test_*.py`): Test individual functions and classes in isolation +- **Integration Tests** (`test_*integration*.py`): Test interactions between components +- **Performance Tests** (`Performance_test.py`): Test system performance and load handling + +### Test Files + +#### Core Functionality Tests +- `test_monitoring_integration.py` - Tests the complete monitoring flow +- `test_risk_assessment.py` - Tests risk assessment functionality +- `test_risk_monitor.py` - Tests risk monitoring features +- `test_search.py` - Tests search functionality +- `test_search_method.py` - Tests different search methods + +#### Extraction Tests +- `test_chunk_extraction.py` - Tests document chunking +- `test_source_extraction.py` - Tests source extraction +- `test_enhanced_source_extraction.py` - Tests enhanced extraction features +- `test_enhanced_sources.py` - Tests various source types + +#### Entity and Graph Tests +- `test_entity_types.py` - Tests entity type handling +- `test_name_variations.py` - Tests name variation detection +- `test_chunk_diagnosis.py` - Tests chunk analysis + +#### Performance and Load Tests +- `Performance_test.py` - Performance benchmarking +- `test_performance_improvement.py` - Performance optimization tests + +#### Integration Tests +- `test_integrationqa.py` - End-to-end integration tests +- `test_commutiesqa.py` - Community QA integration tests + +## Running Tests + +### Using the Test Runner Script + +```bash +# Run all tests +python3 run_tests.py all + +# Run specific test categories +python3 run_tests.py monitoring # Monitoring tests only +python3 run_tests.py risk # Risk assessment tests only +python3 run_tests.py search # Search tests only +python3 run_tests.py extraction # Extraction tests only + +# Run with verbose output +python3 run_tests.py all --verbose +``` + +### Using Pytest Directly + +```bash +# Install pytest if not already installed +pip install pytest pytest-cov + +# Run all tests +pytest tests/ + +# Run specific test file +pytest tests/test_monitoring_integration.py + +# Run with coverage +pytest tests/ --cov=src --cov-report=html + +# Run specific test markers +pytest tests/ -m unit # Unit tests only +pytest tests/ -m integration # Integration tests only +pytest tests/ -m slow # Slow tests only +``` + +### Test Markers + +Tests are automatically categorized using markers: + +- `@pytest.mark.unit` - Unit tests (default) +- `@pytest.mark.integration` - Integration tests +- `@pytest.mark.slow` - Performance/slow tests + +## Test Configuration + +- `conftest.py` - Pytest configuration and fixtures +- `__init__.py` - Package initialization +- Test data directory (if needed) + +## Adding New Tests + +1. Create test file with `test_` prefix +2. Use descriptive test names +3. Add appropriate markers if needed +4. Follow existing test patterns +5. Update this README if adding new test categories + +## Test Data + +If your tests require specific data files, place them in a `tests/data/` directory and use the `test_data_dir` fixture. + +## Coverage + +Run tests with coverage to see code coverage reports: + +```bash +pytest tests/ --cov=src --cov-report=html --cov-report=term +``` + +This will generate both terminal and HTML coverage reports. diff --git a/backend/tests/__init__.py b/backend/tests/__init__.py new file mode 100644 index 000000000..39e6a70e5 --- /dev/null +++ b/backend/tests/__init__.py @@ -0,0 +1,6 @@ +""" +Test package for LLM Graph Builder Backend +""" + +__version__ = "1.0.0" +__author__ = "LLM Graph Builder Team" diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py new file mode 100644 index 000000000..88c879c48 --- /dev/null +++ b/backend/tests/conftest.py @@ -0,0 +1,53 @@ +""" +Pytest configuration and fixtures for LLM Graph Builder Backend tests +""" + +import pytest +import os +import sys +from pathlib import Path + +# Add src to Python path for imports +backend_dir = Path(__file__).parent.parent +src_dir = backend_dir / "src" +sys.path.insert(0, str(src_dir)) + +# Test configuration +pytest_plugins = [] + +def pytest_configure(config): + """Configure pytest with custom markers and settings""" + config.addinivalue_line( + "markers", "integration: marks tests as integration tests" + ) + config.addinivalue_line( + "markers", "unit: marks tests as unit tests" + ) + config.addinivalue_line( + "markers", "slow: marks tests as slow running tests" + ) + +def pytest_collection_modifyitems(config, items): + """Automatically mark tests based on their names""" + for item in items: + # Mark integration tests + if "integration" in item.name.lower(): + item.add_marker(pytest.mark.integration) + + # Mark performance tests + if "performance" in item.name.lower(): + item.add_marker(pytest.mark.slow) + + # Mark unit tests (default) + if not any(marker.name in ['integration', 'slow'] for marker in item.iter_markers()): + item.add_marker(pytest.mark.unit) + +@pytest.fixture(scope="session") +def test_data_dir(): + """Provide path to test data directory""" + return Path(__file__).parent / "data" + +@pytest.fixture(scope="session") +def backend_src_dir(): + """Provide path to backend src directory""" + return Path(__file__).parent.parent / "src" diff --git a/backend/tests/test_adaptive_scoring.py b/backend/tests/test_adaptive_scoring.py new file mode 100644 index 000000000..285def0c4 --- /dev/null +++ b/backend/tests/test_adaptive_scoring.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +""" +Test script to demonstrate adaptive scoring fix for embedding coverage issues +""" + +import os +import sys +from dotenv import load_dotenv + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graph_query import search_nodes, combine_search_results + +load_dotenv() + +def test_adaptive_scoring(): + """Test the adaptive scoring with different embedding coverage scenarios""" + + # Get connection details from environment or use defaults + uri = os.getenv('NEO4J_URI', 'neo4j+ssc://224c5da6.databases.neo4j.io') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', '') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + if not password: + print("โŒ NEO4J_PASSWORD environment variable not set") + return False + + try: + print("๐Ÿ”ง Testing adaptive scoring with embedding coverage...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + # Test search term that should match "Bill Gates" + search_term = "Bil Gate" + expected_match = "Bill Gates" + + print(f"\n๐Ÿ” Testing search term: '{search_term}' -> Expected: '{expected_match}'") + + # Test with current database (low embedding coverage) + print("\n1๏ธโƒฃ Testing with current database (low embedding coverage ~3.8%)") + try: + result = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term=search_term, + node_type="Person", + max_results=5, + prefer_vector=True, + use_hybrid=True + ) + + print(f" Search method: {result['search_method']}") + print(f" Vector coverage: {result['vector_info']['embedding_coverage']:.1%}") + print(f" Total results: {result['total_results']}") + + if result['nodes']: + print(" Top results:") + found_expected = False + for i, node in enumerate(result['nodes'][:3]): + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + vector_score = node.get('similarity_score', 'N/A') + fuzzy_score = node.get('match_ratio', 'N/A') + vector_weight = node.get('vector_weight', 'N/A') + fuzzy_weight = node.get('fuzzy_weight', 'N/A') + search_method = node.get('search_method', 'unknown') + + print(f" {i+1}. {node_name}") + print(f" Combined score: {combined_score}") + print(f" Vector score: {vector_score}") + print(f" Fuzzy score: {fuzzy_score}") + print(f" Vector weight: {vector_weight}") + print(f" Fuzzy weight: {fuzzy_weight}") + print(f" Search method: {search_method}") + + if expected_match.lower() in node_name.lower(): + print(f" โœ… Found expected result!") + if i == 0: + print(f" ๐Ÿ† Expected result is the BEST match!") + else: + print(f" ๐Ÿ“Š Expected result is #{i+1} in ranking") + found_expected = True + break + + if not found_expected: + print(f" โŒ Expected result '{expected_match}' not found in top 3") + + except Exception as e: + print(f" โš ๏ธ Database test failed: {str(e)}") + + # Test adaptive scoring with simulated data + print("\n2๏ธโƒฃ Testing adaptive scoring with simulated data") + + # Simulate low embedding coverage scenario (like current database) + print(" ๐Ÿ“Š Low embedding coverage scenario (3.8%):") + vector_nodes = [ + { + "element_id": "1", + "properties": {"id": "Wendy Sun"}, + "similarity_score": 0.8844, + "search_method": "vector_similarity" + } + ] + + fuzzy_nodes = [ + { + "element_id": "2", + "properties": {"id": "Bill Gates"}, + "match_ratio": 1.0, + "search_method": "fuzzy_text" + }, + { + "element_id": "3", + "properties": {"id": "French Gates"}, + "match_ratio": 0.5, + "search_method": "fuzzy_text" + } + ] + + # Test with low coverage (should favor fuzzy text) + low_coverage_results = combine_search_results(vector_nodes, fuzzy_nodes, 5, 0.038) + print(" Results with 3.8% coverage:") + for i, node in enumerate(low_coverage_results): + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + vector_weight = node.get('vector_weight', 'N/A') + fuzzy_weight = node.get('fuzzy_weight', 'N/A') + print(f" {i+1}. {node_name} (score: {combined_score}, weights: {vector_weight}/{fuzzy_weight})") + + # Test with high coverage (should favor vector) + print(" ๐Ÿ“Š High embedding coverage scenario (80%):") + high_coverage_results = combine_search_results(vector_nodes, fuzzy_nodes, 5, 0.8) + print(" Results with 80% coverage:") + for i, node in enumerate(high_coverage_results): + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + vector_weight = node.get('vector_weight', 'N/A') + fuzzy_weight = node.get('fuzzy_weight', 'N/A') + print(f" {i+1}. {node_name} (score: {combined_score}, weights: {vector_weight}/{fuzzy_weight})") + + # Test with medium coverage + print(" ๐Ÿ“Š Medium embedding coverage scenario (30%):") + medium_coverage_results = combine_search_results(vector_nodes, fuzzy_nodes, 5, 0.3) + print(" Results with 30% coverage:") + for i, node in enumerate(medium_coverage_results): + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + vector_weight = node.get('vector_weight', 'N/A') + fuzzy_weight = node.get('fuzzy_weight', 'N/A') + print(f" {i+1}. {node_name} (score: {combined_score}, weights: {vector_weight}/{fuzzy_weight})") + + print("\nโœ… Adaptive scoring tests completed!") + return True + + except Exception as e: + print(f"โŒ Test failed with error: {str(e)}") + return False + +if __name__ == "__main__": + success = test_adaptive_scoring() + sys.exit(0 if success else 1) diff --git a/backend/tests/test_bill_gates_sources.py b/backend/tests/test_bill_gates_sources.py new file mode 100644 index 000000000..2bf67600c --- /dev/null +++ b/backend/tests/test_bill_gates_sources.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +""" +Test Bill Gates Risk Assessment Sources + +This script specifically tests the Bill Gates risk assessment to see if +the enhanced source extraction is working and showing document names +instead of "Chunk X" references. +""" + +import os +import sys +import logging +from dotenv import load_dotenv + +# Add src to path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.risk_assessment import analyze_risk +from src.shared.common_fn import create_graph_database_connection + +# Configure logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def test_bill_gates_risk_assessment(): + """ + Test Bill Gates risk assessment with enhanced source extraction. + """ + + # Load environment variables + load_dotenv() + + # Get database connection details + uri = os.getenv('NEO4J_URI', 'bolt://localhost:7687') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', 'password') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + try: + print("๐Ÿ” TESTING BILL GATES RISK ASSESSMENT SOURCES") + print("=" * 60) + + # Define risk indicators (same as your example) + risk_indicators = { + "Foreign State Influence": 80, + "Dual-Use Technology Exposure": 70, + "Compliance with Canadian Research Security Policies": 60, + "International Collaboration Patterns": 50, + "Funding Sources Transparency": 40, + "Export Control Compliance": 45, + "Intellectual Property Protection": 35, + "Research Data Security": 30 + } + + print(f"๐Ÿ“‹ Risk Assessment Parameters:") + print(f" Entity: Bill Gates (Person)") + print(f" Risk Indicators: {len(risk_indicators)}") + print(f" Depth: 4") + print(f" Max Results: 10") + print() + + # Run risk assessment + print("๐Ÿ”„ Running risk assessment...") + result = analyze_risk( + uri=uri, + username=username, + password=password, + database=database, + entity_name="Bill Gates", + entity_type="Person", + risk_indicators=risk_indicators, + depth=4, + max_results=10 + ) + + if 'error' in result: + print(f"โŒ Error: {result['error']}") + return + + # Display results + print("\n๐Ÿ“Š RISK ASSESSMENT RESULTS") + print("=" * 60) + + # Overall assessment + overall_score = result.get('calculation', {}).get('overallScore', 'N/A') + traffic_light = result.get('finalAssessment', {}).get('trafficLight', 'N/A') + + print(f"๐ŸŽฏ Overall Score: {overall_score}") + print(f"๐Ÿšฆ Status: {traffic_light}") + print() + + # Risk indicators with sources + risk_assessments = result.get('riskAssessments', []) + + print("๐Ÿ“‹ RISK INDICATORS AND SOURCES") + print("-" * 60) + + for assessment in risk_assessments: + indicator = assessment.get('indicator', 'Unknown') + score = assessment.get('score', 'N/A') + weight = assessment.get('weight', 'N/A') + sources = assessment.get('sources', []) + + print(f"๐Ÿ” {indicator}") + print(f" Score: {score}/5") + print(f" Weight: {weight}") + print(f" Sources: {sources}") + print() + + # Analysis metadata + metadata = result.get('analysis_metadata', {}) + chunks_analyzed = metadata.get('chunks_analyzed', 0) + search_method = metadata.get('search_method', 'Unknown') + + print("๐Ÿ“Š ANALYSIS METADATA") + print("-" * 60) + print(f" Chunks Analyzed: {chunks_analyzed}") + print(f" Search Method: {search_method}") + + # Source analysis + print("\n๐Ÿ” SOURCE ANALYSIS") + print("-" * 60) + + source_types = {} + total_sources = 0 + + for assessment in risk_assessments: + sources = assessment.get('sources', []) + for source in sources: + total_sources += 1 + if source == 'nil': + source_types['nil'] = source_types.get('nil', 0) + 1 + elif source.startswith('Chunk'): + source_types['Chunk Reference'] = source_types.get('Chunk Reference', 0) + 1 + elif source.startswith('http'): + source_types['URL'] = source_types.get('URL', 0) + 1 + elif source.startswith('Document:'): + source_types['Document Name'] = source_types.get('Document Name', 0) + 1 + else: + source_types['Other'] = source_types.get('Other', 0) + 1 + + print(f"๐Ÿ“Š Total Sources: {total_sources}") + for source_type, count in source_types.items(): + percentage = (count / total_sources * 100) if total_sources > 0 else 0 + print(f" {source_type}: {count} ({percentage:.1f}%)") + + # Summary + print("\n๐Ÿ“ˆ SUMMARY") + print("=" * 60) + + if source_types.get('Document Name', 0) > 0: + print("โœ… Enhanced source extraction is working!") + print(" Document names are being shown instead of 'Chunk X'") + elif source_types.get('URL', 0) > 0: + print("โœ… Enhanced source extraction is working!") + print(" Actual URLs are being shown") + elif source_types.get('Chunk Reference', 0) > 0: + print("โš ๏ธ Still showing 'Chunk X' references") + print(" This suggests chunks don't have URL properties") + else: + print("โ„น๏ธ Mostly 'nil' sources (no evidence found)") + + if source_types.get('nil', 0) > 0: + print(f" {source_types['nil']} indicators have 'nil' sources (no evidence)") + + except Exception as e: + logger.error(f"Error testing Bill Gates risk assessment: {str(e)}") + print(f"โŒ Error: {str(e)}") + finally: + if 'graph' in locals(): + graph.close() + +if __name__ == "__main__": + test_bill_gates_risk_assessment() diff --git a/backend/tests/test_chunk_diagnosis.py b/backend/tests/test_chunk_diagnosis.py new file mode 100644 index 000000000..e2e45987b --- /dev/null +++ b/backend/tests/test_chunk_diagnosis.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +""" +Diagnostic script to examine chunk extraction and source information. +""" + +import sys +import os +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from src.risk_assessment import extract_chunks_from_subgraph, analyze_risk +import logging +import json + +# Set up logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +def test_chunk_diagnosis(): + """Diagnose chunk extraction and source information.""" + + # Connection parameters - you'll need to set your password + uri = "neo4j+ssc://224c5da6.databases.neo4j.io" + username = "neo4j" + password = "" # Add your password here + database = "neo4j" + + if not password: + print("โŒ Please set the password in the script") + return + + print("๐Ÿ” Diagnosing chunk extraction and source information...") + + try: + # Test the full risk assessment to see what chunks are extracted + risk_indicators = { + "Foreign State Influence": 80, + "Dual-Use Technology Exposure": 70, + "Compliance with Canadian Research Security Policies": 60, + "International Collaboration Patterns": 50, + "Funding Sources Transparency": 40 + } + + print("\n๐Ÿ“‹ Running full risk assessment for Bill Gates...") + result = analyze_risk( + uri=uri, + username=username, + password=password, + database=database, + entity_name="Bill Gates", + entity_type="Person", + risk_indicators=risk_indicators, + depth=4, + max_results=10 + ) + + if 'error' in result: + print(f"โŒ Error: {result['error']}") + return + + print(f"\nโœ… Risk assessment completed") + print(f"๐Ÿ“Š Analysis metadata:") + metadata = result.get('analysis_metadata', {}) + for key, value in metadata.items(): + print(f" {key}: {value}") + + # Save the full result for analysis + with open('chunk_diagnosis_result.json', 'w') as f: + json.dump(result, f, indent=2, default=str) + + print(f"\n๐Ÿ’พ Full result saved to: chunk_diagnosis_result.json") + + # Analyze the risk assessments to see source patterns + print(f"\n๐Ÿ“‹ Analyzing source patterns in risk assessments:") + risk_assessments = result.get('riskAssessments', []) + + for assessment in risk_assessments: + indicator = assessment.get('indicator', 'Unknown') + sources = assessment.get('sources', []) + explanation = assessment.get('explanation', '') + + print(f"\n {indicator}:") + print(f" Sources: {sources}") + print(f" Explanation preview: {explanation[:100]}...") + + # Check if sources are "nil" and why + if sources == ["nil"]: + print(f" โš ๏ธ No sources found - this indicates no evidence in chunks") + elif "Chunk" in str(sources): + print(f" โœ… Chunk references found - chunks are being used") + elif any(source.startswith(('http://', 'https://', 'Document:')) for source in sources): + print(f" โœ… Actual sources found - URLs or document names present") + + # Test chunk extraction separately + print(f"\n๐Ÿ”ง Testing chunk extraction separately...") + from src.graph_query import search_and_get_subgraph + + subgraph_data = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term="Bill Gates", + node_type="Person", + depth=4, + max_results=10, + extract_best_match_only=True, + preserve_text=True + ) + + chunks = extract_chunks_from_subgraph(subgraph_data) + + print(f"\n๐Ÿ“ Extracted {len(chunks)} chunks:") + for i, chunk in enumerate(chunks): + print(f"\n Chunk {i+1}:") + print(f" ID: {chunk['chunk_id']}") + print(f" Document: {chunk['document_name'] or chunk['document_id']}") + print(f" Source: {chunk['source']}") + print(f" Text length: {len(chunk['text'])} characters") + print(f" Text preview: {chunk['text'][:100]}...") + + # Check source quality + if chunk['source'].startswith('http'): + print(f" โœ… Has URL source") + elif chunk['source'].startswith('Document:'): + print(f" โœ… Has document source") + elif chunk['source'].startswith('Chunk'): + print(f" โš ๏ธ Generic chunk reference") + else: + print(f" โ“ Unknown source format") + + except Exception as e: + print(f"โŒ Error: {str(e)}") + logging.exception("Error in chunk diagnosis") + +if __name__ == "__main__": + test_chunk_diagnosis() diff --git a/backend/tests/test_chunk_extraction.py b/backend/tests/test_chunk_extraction.py new file mode 100644 index 000000000..6150733e9 --- /dev/null +++ b/backend/tests/test_chunk_extraction.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +""" +Test script to verify chunk extraction in risk assessment. +""" + +import sys +import os +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from src.risk_assessment import extract_chunks_from_subgraph +import logging + +# Set up logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +def test_chunk_extraction(): + """Test the chunk extraction function with sample data.""" + + # Sample subgraph data structure + sample_subgraph_data = { + 'subgraphs': [ + { + 'nodes': [ + { + 'element_id': 'node1', + 'labels': ['Person'], + 'properties': { + 'id': 'Bill Gates', + 'name': 'Bill Gates' + } + }, + { + 'element_id': 'node2', + 'labels': ['Chunk'], + 'properties': { + 'id': 'chunk1', + 'text': 'Bill Gates is a co-founder of Microsoft Corporation and a prominent philanthropist.', + 'source': 'document1.pdf', + 'document_id': 'doc1' + } + }, + { + 'element_id': 'node3', + 'labels': ['DocumentChunk'], + 'properties': { + 'id': 'chunk2', + 'content': 'Microsoft was founded in 1975 by Bill Gates and Paul Allen.', + 'source': 'document2.pdf', + 'document_id': 'doc2' + } + }, + { + 'element_id': 'node4', + 'labels': ['Organization'], + 'properties': { + 'id': 'Microsoft', + 'name': 'Microsoft Corporation' + } + } + ], + 'relationships': [] + } + ] + } + + print("Testing chunk extraction...") + print(f"Sample subgraph has {len(sample_subgraph_data['subgraphs'][0]['nodes'])} nodes") + + # Extract chunks + chunks = extract_chunks_from_subgraph(sample_subgraph_data) + + print(f"\nExtracted {len(chunks)} chunks:") + for i, chunk in enumerate(chunks): + print(f"\nChunk {i+1}:") + print(f" ID: {chunk['chunk_id']}") + print(f" Text: {chunk['text'][:100]}...") + print(f" Source: {chunk['source']}") + print(f" Document: {chunk['document_id']}") + + return chunks + +if __name__ == "__main__": + test_chunk_extraction() diff --git a/backend/test_commutiesqa.py b/backend/tests/test_commutiesqa.py similarity index 100% rename from backend/test_commutiesqa.py rename to backend/tests/test_commutiesqa.py diff --git a/backend/tests/test_enhanced_source_extraction.py b/backend/tests/test_enhanced_source_extraction.py new file mode 100644 index 000000000..fae08f703 --- /dev/null +++ b/backend/tests/test_enhanced_source_extraction.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +""" +Test Enhanced Source Extraction + +This script tests whether the enhanced source extraction is working and +returning actual source URLs instead of just chunk references. +""" + +import os +import sys +import logging +from dotenv import load_dotenv + +# Add src to path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.risk_assessment import extract_chunks_from_subgraph +from src.graph_query import search_and_get_subgraph +from src.shared.common_fn import create_graph_database_connection + +# Configure logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def test_enhanced_source_extraction(): + """ + Test the enhanced source extraction functionality. + """ + + # Load environment variables + load_dotenv() + + # Get database connection details + uri = os.getenv('NEO4J_URI', 'bolt://localhost:7687') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', 'password') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + try: + # Create database connection + graph = create_graph_database_connection(uri, username, password, database) + + print("๐Ÿ” TESTING ENHANCED SOURCE EXTRACTION") + print("=" * 60) + + # Test with Apple (organization) + print("\n๐Ÿ“‹ TEST 1: Apple (Organization)") + print("-" * 40) + + try: + # Search for Apple and get subgraph + subgraph_data = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term="Apple", + node_type="Organization", + depth=4, + max_results=10, + extract_best_match_only=True, + preserve_text=True + ) + + if subgraph_data.get('subgraphs'): + print(f"โœ… Found subgraph for Apple") + print(f" Best match: {subgraph_data.get('best_match', {}).get('node_name', 'Unknown')}") + print(f" Search method: {subgraph_data.get('best_match', {}).get('search_method', 'Unknown')}") + + # Extract chunks with enhanced source extraction + chunks = extract_chunks_from_subgraph(subgraph_data) + + print(f"\n๐Ÿ“„ Extracted {len(chunks)} chunks:") + for i, chunk in enumerate(chunks, 1): + print(f" {i}. Source: {chunk['source']}") + print(f" Document: {chunk['document_name']}") + print(f" Text length: {len(chunk['text'])} chars") + print() + + # Analyze source types + source_types = {} + for chunk in chunks: + source = chunk['source'] + if source.startswith('http'): + source_types['URL'] = source_types.get('URL', 0) + 1 + elif source.startswith('Document:'): + source_types['Document'] = source_types.get('Document', 0) + 1 + elif source.startswith('Chunk'): + source_types['Chunk'] = source_types.get('Chunk', 0) + 1 + else: + source_types['Other'] = source_types.get('Other', 0) + 1 + + print("๐Ÿ“Š Source Type Analysis:") + for source_type, count in source_types.items(): + print(f" {source_type}: {count}") + + else: + print("โŒ No subgraph found for Apple") + + except Exception as e: + print(f"โŒ Error testing Apple: {str(e)}") + + # Test with Bill Gates (person) + print("\n๐Ÿ“‹ TEST 2: Bill Gates (Person)") + print("-" * 40) + + try: + # Search for Bill Gates and get subgraph + subgraph_data = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term="Bill Gates", + node_type="Person", + depth=4, + max_results=10, + extract_best_match_only=True, + preserve_text=True + ) + + if subgraph_data.get('subgraphs'): + print(f"โœ… Found subgraph for Bill Gates") + print(f" Best match: {subgraph_data.get('best_match', {}).get('node_name', 'Unknown')}") + print(f" Search method: {subgraph_data.get('best_match', {}).get('search_method', 'Unknown')}") + + # Extract chunks with enhanced source extraction + chunks = extract_chunks_from_subgraph(subgraph_data) + + print(f"\n๐Ÿ“„ Extracted {len(chunks)} chunks:") + for i, chunk in enumerate(chunks, 1): + print(f" {i}. Source: {chunk['source']}") + print(f" Document: {chunk['document_name']}") + print(f" Text length: {len(chunk['text'])} chars") + print() + + # Analyze source types + source_types = {} + for chunk in chunks: + source = chunk['source'] + if source.startswith('http'): + source_types['URL'] = source_types.get('URL', 0) + 1 + elif source.startswith('Document:'): + source_types['Document'] = source_types.get('Document', 0) + 1 + elif source.startswith('Chunk'): + source_types['Chunk'] = source_types.get('Chunk', 0) + 1 + else: + source_types['Other'] = source_types.get('Other', 0) + 1 + + print("๐Ÿ“Š Source Type Analysis:") + for source_type, count in source_types.items(): + print(f" {source_type}: {count}") + + else: + print("โŒ No subgraph found for Bill Gates") + + except Exception as e: + print(f"โŒ Error testing Bill Gates: {str(e)}") + + # Summary + print("\n๐Ÿ“Š SUMMARY") + print("=" * 60) + print("โœ… Enhanced source extraction is working!") + print("๐Ÿ“ˆ Expected improvements:") + print(" - More actual URLs instead of 'Chunk X'") + print(" - Better document name references") + print(" - Improved source attribution in risk assessments") + + except Exception as e: + logger.error(f"Error testing enhanced source extraction: {str(e)}") + print(f"โŒ Error: {str(e)}") + finally: + if 'graph' in locals(): + graph.close() + +if __name__ == "__main__": + test_enhanced_source_extraction() diff --git a/backend/tests/test_enhanced_sources.py b/backend/tests/test_enhanced_sources.py new file mode 100644 index 000000000..79edbf279 --- /dev/null +++ b/backend/tests/test_enhanced_sources.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +""" +Test script to verify enhanced source extraction functionality. +""" + +import sys +import os +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from src.risk_assessment import extract_chunks_from_subgraph +import logging + +# Set up logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +def test_enhanced_source_extraction(): + """Test the enhanced source extraction with various scenarios.""" + + # Test case 1: Chunks with URLs + test_data_1 = { + 'subgraphs': [{ + 'nodes': [ + { + 'element_id': 'doc1', + 'labels': ['Document'], + 'properties': { + 'id': 'doc1', + 'name': 'Apple stock during pandemic.pdf', + 'url': 'https://example.com/apple-stock-pandemic.pdf' + } + }, + { + 'element_id': 'chunk1', + 'labels': ['Chunk'], + 'properties': { + 'id': 'chunk1', + 'text': 'Bill Gates is a co-founder of Microsoft Corporation.', + 'document_id': 'doc1' + } + } + ], + 'relationships': [] + }] + } + + # Test case 2: Chunks with document names but no URLs + test_data_2 = { + 'subgraphs': [{ + 'nodes': [ + { + 'element_id': 'doc2', + 'labels': ['Document'], + 'properties': { + 'id': 'doc2', + 'name': 'Microsoft financial report.pdf' + } + }, + { + 'element_id': 'chunk2', + 'labels': ['Chunk'], + 'properties': { + 'id': 'chunk2', + 'text': 'Microsoft was founded in 1975 by Bill Gates and Paul Allen.', + 'document_id': 'doc2' + } + } + ], + 'relationships': [] + }] + } + + # Test case 3: Chunks with no document info + test_data_3 = { + 'subgraphs': [{ + 'nodes': [ + { + 'element_id': 'chunk3', + 'labels': ['Chunk'], + 'properties': { + 'id': 'chunk3', + 'text': 'Bill Gates is known for his philanthropic work.', + 'source': 'unknown source' + } + } + ], + 'relationships': [] + }] + } + + test_cases = [ + ("Chunks with URLs", test_data_1), + ("Chunks with document names", test_data_2), + ("Chunks with no document info", test_data_3) + ] + + for test_name, test_data in test_cases: + print(f"\n๐Ÿงช Testing: {test_name}") + print("=" * 50) + + chunks = extract_chunks_from_subgraph(test_data) + + print(f"Extracted {len(chunks)} chunks:") + for i, chunk in enumerate(chunks): + print(f"\n Chunk {i+1}:") + print(f" ID: {chunk['chunk_id']}") + print(f" Document: {chunk['document_name'] or chunk['document_id']}") + print(f" Source: {chunk['source']}") + print(f" Text: {chunk['text'][:50]}...") + + # Test the prompt template rendering + print(f"\n๐Ÿ“ Testing prompt template rendering...") + from src.risk_assessment import RISK_ASSESSMENT_PROMPT + from jinja2 import Template + + template = Template(RISK_ASSESSMENT_PROMPT) + + # Sample data for template + sample_context = { + 'entity_name': 'Bill Gates', + 'entity_type': 'Person', + 'risk_indicators': {'Foreign State Influence': 80, 'Dual-Use Technology Exposure': 70}, + 'chunks': [ + { + 'text': 'Bill Gates is a co-founder of Microsoft Corporation.', + 'source': 'https://example.com/apple-stock-pandemic.pdf', + 'document_name': 'Apple stock during pandemic.pdf' + }, + { + 'text': 'Microsoft was founded in 1975 by Bill Gates and Paul Allen.', + 'source': 'Document: Microsoft financial report.pdf', + 'document_name': 'Microsoft financial report.pdf' + } + ], + 'subgraph_info': {'total_nodes': 139, 'total_relationships': 276, 'entity_connections': 15} + } + + rendered_prompt = template.render(**sample_context) + + print(f"\nRendered prompt preview (first 500 chars):") + print(rendered_prompt[:500] + "...") + + # Check if source instructions are included + if "Source Reference Instructions" in rendered_prompt: + print("โœ… Source reference instructions included in prompt") + else: + print("โŒ Source reference instructions missing from prompt") + +if __name__ == "__main__": + test_enhanced_source_extraction() diff --git a/backend/tests/test_entity_types.py b/backend/tests/test_entity_types.py new file mode 100644 index 000000000..dce11cb8e --- /dev/null +++ b/backend/tests/test_entity_types.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +""" +Test script to check what entity types are available in the database for search +""" + +import os +import sys +from dotenv import load_dotenv + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graph_query import diagnose_database_entities, search_nodes + +load_dotenv() + +def test_entity_types(): + """Check what entity types are available in the database""" + + # Get connection details from environment or use defaults + uri = os.getenv('NEO4J_URI', 'neo4j+ssc://224c5da6.databases.neo4j.io') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', '') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + if not password: + print("โŒ NEO4J_PASSWORD environment variable not set") + return False + + try: + print("๐Ÿ” Checking available entity types in the database...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + # Get database diagnosis + print("\n1๏ธโƒฃ Getting database entity diagnosis...") + diagnosis = diagnose_database_entities(uri, username, password, database) + + print(f"\n๐Ÿ“Š Found {diagnosis['total_entity_types']} entity types:") + for entity_type in diagnosis['entity_types']: + print(f" โ€ข {entity_type['type']}: {entity_type['count']} entities") + + print(f"\n๐Ÿ“‹ Sample entities:") + for entity in diagnosis['sample_entities']: + labels = entity['labels'] + entity_id = entity['id'] + entity_name = entity.get('name', 'N/A') + entity_description = entity.get('description', 'N/A') + entity_type = entity.get('type', 'N/A') + + print(f" โ€ข Labels: {labels}") + print(f" ID: {entity_id}") + print(f" Name: {entity_name}") + print(f" Description: {entity_description}") + print(f" Type: {entity_type}") + print() + + # Test search for different entity types + print("2๏ธโƒฃ Testing search for different entity types...") + + # Test search for each entity type + for entity_type in diagnosis['entity_types'][:5]: # Test first 5 types + entity_type_name = entity_type['type'] + entity_count = entity_type['count'] + + print(f"\n๐Ÿ” Testing search for entity type: '{entity_type_name}' ({entity_count} entities)") + + try: + # Try a generic search term + search_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term="test", # Generic search term + node_type=entity_type_name, + max_results=3, + prefer_vector=True, + use_hybrid=True + ) + + print(f" Search method: {search_results['search_method']}") + print(f" Total results: {search_results['total_results']}") + print(f" Vector coverage: {search_results['vector_info']['embedding_coverage']:.1%}") + + if search_results['nodes']: + print(" Top results:") + for i, node in enumerate(search_results['nodes'][:3]): + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + print(f" {i+1}. {node_name} (score: {combined_score})") + else: + print(" โŒ No results found") + + except Exception as e: + print(f" โš ๏ธ Search failed: {str(e)}") + + # Test specific entity type searches + print("\n3๏ธโƒฃ Testing specific entity type searches...") + + # Common entity types to test + test_cases = [ + {"type": "Person", "search_term": "Bill"}, + {"type": "Organization", "search_term": "Microsoft"}, + {"type": "Company", "search_term": "Apple"}, + {"type": "Institution", "search_term": "University"}, + {"type": "Location", "search_term": "New York"}, + {"type": "Country", "search_term": "USA"}, + {"type": "City", "search_term": "London"}, + {"type": "Technology", "search_term": "AI"}, + {"type": "Product", "search_term": "iPhone"}, + {"type": "Event", "search_term": "Conference"} + ] + + for test_case in test_cases: + entity_type = test_case["type"] + search_term = test_case["search_term"] + + print(f"\n๐Ÿ” Testing '{entity_type}' search with term '{search_term}'") + + try: + search_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term=search_term, + node_type=entity_type, + max_results=3, + prefer_vector=True, + use_hybrid=True + ) + + print(f" Results: {search_results['total_results']} found") + if search_results['nodes']: + for i, node in enumerate(search_results['nodes'][:2]): + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + print(f" {i+1}. {node_name} (score: {combined_score})") + + except Exception as e: + print(f" โš ๏ธ Search failed: {str(e)}") + + print("\nโœ… Entity type testing completed!") + return True + + except Exception as e: + print(f"โŒ Test failed with error: {str(e)}") + return False + +if __name__ == "__main__": + success = test_entity_types() + sys.exit(0 if success else 1) diff --git a/backend/test_integrationqa.py b/backend/tests/test_integrationqa.py similarity index 100% rename from backend/test_integrationqa.py rename to backend/tests/test_integrationqa.py diff --git a/backend/tests/test_monitoring_delete.py b/backend/tests/test_monitoring_delete.py new file mode 100644 index 000000000..ee8699c85 --- /dev/null +++ b/backend/tests/test_monitoring_delete.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +""" +Test script to debug monitoring delete functionality +""" + +import asyncio +import os +import sys +from datetime import datetime + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.monitoring_service import MonitoringService +from src.shared.common_fn import create_graph_database_connection + +async def test_monitoring_delete(): + """Test the monitoring delete functionality""" + + # Connect to Neo4j using environment variables + uri = os.getenv("NEO4J_URI", "neo4j+ssc://224c5da6.databases.neo4j.io") + userName = os.getenv("NEO4J_USERNAME", "neo4j") + password = os.getenv("NEO4J_PASSWORD", "_18dKuxBBytBxPuKZP5snPvXelfYs7uQKWcA_A9HUHU") + database = os.getenv("NEO4J_DATABASE", "neo4j") + + print(f"Connecting to Neo4j: {uri}") + print(f"Username: {userName}") + print(f"Database: {database}") + graph = create_graph_database_connection(uri, userName, password, database) + + # Create monitoring service + monitoring_service = MonitoringService(graph) + + print("=== Testing Monitoring Delete Functionality ===") + + # 1. Check what entities exist + print("\n1. Current monitored entities:") + entities = monitoring_service.get_monitored_entities_from_db() + for entity in entities: + print(f" - ID: {entity['id']}, Name: {entity['name']}, Type: {entity['type']}") + + # 2. Try to delete a specific entity (if any exist) + if entities: + test_entity_id = entities[0]['id'] + print(f"\n2. Attempting to delete entity: {test_entity_id}") + + success = await monitoring_service.remove_monitored_entity(test_entity_id) + print(f" Delete result: {success}") + + # 3. Check if entity was actually deleted + print("\n3. Entities after deletion:") + remaining_entities = await monitoring_service.get_monitored_entities_from_db() + for entity in remaining_entities: + print(f" - ID: {entity['id']}, Name: {entity['name']}, Type: {entity['type']}") + else: + print("\n2. No entities to test deletion with") + + # 4. Test with a non-existent ID + print("\n4. Testing deletion with non-existent ID:") + fake_id = "fake_entity_123" + success = await monitoring_service.remove_monitored_entity(fake_id) + print(f" Delete result for fake ID: {success}") + +if __name__ == "__main__": + asyncio.run(test_monitoring_delete()) diff --git a/backend/tests/test_monitoring_integration.py b/backend/tests/test_monitoring_integration.py new file mode 100644 index 000000000..50f7e65f0 --- /dev/null +++ b/backend/tests/test_monitoring_integration.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +""" +Test script to verify the enhanced monitoring integration flow +Tests: subgraph monitoring -> risk assessment -> alert generation -> PostgreSQL storage +""" + +import asyncio +import logging +import sys +import os + +# Add src to path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.subgraph_monitor import SubgraphMonitor +from src.monitoring_service_pg import MonitoringServicePG + +# Set up logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +async def test_monitoring_integration(): + """Test the complete monitoring flow""" + + print("๐Ÿงช Testing Enhanced Monitoring Integration Flow") + print("=" * 60) + + try: + # Test 1: Initialize monitoring service + print("\n1๏ธโƒฃ Testing Monitoring Service Initialization...") + monitoring_service = MonitoringServicePG() + + # Check if schema exists + schema_ok = monitoring_service.initialize_monitoring_schema() + if schema_ok: + print("โœ… Monitoring schema initialized successfully") + else: + print("โš ๏ธ Monitoring schema not fully initialized - run migrations first") + + # Test 2: Get monitored entities + print("\n2๏ธโƒฃ Testing Monitored Entities Retrieval...") + entities = monitoring_service.get_monitored_entities_from_db() + print(f"๐Ÿ“Š Found {len(entities)} monitored entities:") + for entity in entities: + print(f" - {entity['name']} ({entity['type']}) - Risk threshold: {entity['risk_threshold']}") + + # Test 3: Test subgraph monitor + print("\n3๏ธโƒฃ Testing Subgraph Monitor...") + subgraph_monitor = SubgraphMonitor() + + # Get entities from subgraph monitor + monitor_entities = subgraph_monitor.get_monitored_entities() + print(f"๐Ÿ“Š Subgraph monitor found {len(monitor_entities)} entities:") + for entity in monitor_entities: + print(f" - {entity['name']} - Status: {entity['status']}") + + # Test 4: Test monitoring without Neo4j (should work with basic monitoring) + print("\n4๏ธโƒฃ Testing Basic Monitoring (without Neo4j)...") + try: + # This should work even without Neo4j connection + basic_result = await monitoring_service.check_entity_risk_changes( + [entity['name'] for entity in entities[:2]], # Test with first 2 entities + "openai_gpt_4o" + ) + print(f"โœ… Basic monitoring completed: {basic_result['entities_checked']} entities checked") + if 'entities_with_changes' in basic_result: + print(f"๐Ÿ“ˆ Entities with changes: {len(basic_result['entities_with_changes'])}") + except Exception as e: + print(f"โš ๏ธ Basic monitoring test failed: {str(e)}") + + print("\n" + "=" * 60) + print("๐ŸŽฏ Monitoring Integration Test Summary:") + print(f" โ€ข Schema initialized: {'โœ…' if schema_ok else 'โš ๏ธ'}") + print(f" โ€ข Monitored entities: {len(entities)}") + print(f" โ€ข Subgraph monitor entities: {len(monitor_entities)}") + print(f" โ€ข Basic monitoring: {'โœ…' if 'basic_result' in locals() else 'โš ๏ธ'}") + + if schema_ok and entities and monitor_entities: + print("\n๐ŸŽ‰ All core components are working! The monitoring flow should work when:") + print(" 1. Neo4j connection is available") + print(" 2. Documents are processed") + print(" 3. Subgraph changes are detected") + print(" 4. Risk assessment is triggered") + print(" 5. Alerts are generated and stored in PostgreSQL") + else: + print("\nโš ๏ธ Some components need attention. Check the logs above.") + + except Exception as e: + print(f"\nโŒ Test failed with error: {str(e)}") + logger.exception("Test failed") + return False + + return True + +if __name__ == "__main__": + print("๐Ÿš€ Starting Monitoring Integration Test...") + success = asyncio.run(test_monitoring_integration()) + + if success: + print("\nโœ… Test completed successfully!") + sys.exit(0) + else: + print("\nโŒ Test failed!") + sys.exit(1) diff --git a/backend/tests/test_name_variations.py b/backend/tests/test_name_variations.py new file mode 100644 index 000000000..ec2360f2b --- /dev/null +++ b/backend/tests/test_name_variations.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +""" +Test script for name variation search (e.g., "Bill Gates" vs "Billy Gates") +""" + +import os +import sys +from dotenv import load_dotenv + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graph_query import search_nodes, check_vector_availability + +load_dotenv() + +def test_name_variations(): + """Test how the search handles name variations""" + + # Get connection details from environment or use defaults + uri = os.getenv('NEO4J_URI', 'neo4j+ssc://224c5da6.databases.neo4j.io') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', '') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + if not password: + print("โŒ NEO4J_PASSWORD environment variable not set") + return False + + try: + print("๐Ÿ” Testing name variation search functionality...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + # Test cases for name variations + test_cases = [ + { + "search_term": "Billy Gates", + "expected": "Bill Gates", + "description": "Nickname variation" + }, + { + "search_term": "William Gates", + "expected": "Bill Gates", + "description": "Full name variation" + }, + { + "search_term": "Gates Bill", + "expected": "Bill Gates", + "description": "Reversed name order" + }, + { + "search_term": "Bill", + "expected": "Bill Gates", + "description": "Partial name" + }, + { + "search_term": "Gates", + "expected": "Bill Gates", + "description": "Last name only" + } + ] + + print(f"\n๐Ÿ“‹ Testing {len(test_cases)} name variation scenarios...") + + for i, test_case in enumerate(test_cases, 1): + print(f"\n{i}. Testing: '{test_case['search_term']}' -> Expected: '{test_case['expected']}'") + print(f" Description: {test_case['description']}") + + # Test with hybrid search (default) + print(" ๐Ÿ”„ Testing with hybrid search...") + hybrid_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term=test_case['search_term'], + node_type="Person", + max_results=5, + prefer_vector=True, + use_hybrid=True + ) + + print(f" Search method: {hybrid_results['search_method']}") + print(f" Total results: {hybrid_results['total_results']}") + + if hybrid_results['nodes']: + print(" Top results:") + for j, node in enumerate(hybrid_results['nodes'][:3]): + node_name = node.get('properties', {}).get('id', 'Unknown') + combined_score = node.get('combined_score', 'N/A') + similarity_score = node.get('similarity_score', 'N/A') + match_ratio = node.get('match_ratio', 'N/A') + + print(f" {j+1}. {node_name}") + print(f" Combined score: {combined_score}") + print(f" Vector similarity: {similarity_score}") + print(f" Fuzzy match ratio: {match_ratio}") + + # Check if we found the expected result + if test_case['expected'].lower() in node_name.lower(): + print(f" โœ… Found expected result!") + break + else: + print(f" โŒ Expected result '{test_case['expected']}' not found in top 3") + else: + print(" โŒ No results found") + + # Test with vector-only search + print(" ๐Ÿง  Testing with vector-only search...") + vector_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term=test_case['search_term'], + node_type="Person", + max_results=5, + prefer_vector=True, + use_hybrid=False + ) + + print(f" Search method: {vector_results['search_method']}") + print(f" Total results: {vector_results['total_results']}") + + if vector_results['nodes']: + print(" Top vector results:") + for j, node in enumerate(vector_results['nodes'][:3]): + node_name = node.get('properties', {}).get('id', 'Unknown') + similarity_score = node.get('similarity_score', 'N/A') + print(f" {j+1}. {node_name} (similarity: {similarity_score})") + + # Test with fuzzy text-only search + print(" ๐Ÿ”ค Testing with fuzzy text-only search...") + fuzzy_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term=test_case['search_term'], + node_type="Person", + max_results=5, + prefer_vector=False, + use_hybrid=False + ) + + print(f" Search method: {fuzzy_results['search_method']}") + print(f" Total results: {fuzzy_results['total_results']}") + + if fuzzy_results['nodes']: + print(" Top fuzzy text results:") + for j, node in enumerate(fuzzy_results['nodes'][:3]): + node_name = node.get('properties', {}).get('id', 'Unknown') + match_ratio = node.get('match_ratio', 'N/A') + print(f" {j+1}. {node_name} (match ratio: {match_ratio})") + + print("\n๐ŸŽ‰ Name variation tests completed!") + return True + + except Exception as e: + print(f"โŒ Test failed with error: {str(e)}") + return False + +if __name__ == "__main__": + success = test_name_variations() + sys.exit(0 if success else 1) diff --git a/backend/tests/test_performance_improvement.py b/backend/tests/test_performance_improvement.py new file mode 100644 index 000000000..ff183c65c --- /dev/null +++ b/backend/tests/test_performance_improvement.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +""" +Test script to demonstrate performance improvement from extracting only the best match +""" + +import os +import sys +import time +from dotenv import load_dotenv + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graph_query import search_and_get_subgraph + +load_dotenv() + +def test_performance_improvement(): + """Test the performance improvement from extracting only the best match""" + + # Get connection details from environment or use defaults + uri = os.getenv('NEO4J_URI', 'neo4j+ssc://224c5da6.databases.neo4j.io') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', '') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + if not password: + print("โŒ NEO4J_PASSWORD environment variable not set") + return False + + try: + print("๐Ÿš€ Testing performance improvement with best match extraction...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + # Test search term that should return multiple results + search_term = "Bil Gate" # Should match "Bill Gates" and potentially others + + print(f"\n๐Ÿ” Testing search term: '{search_term}'") + + # Test 1: Extract from best match only (fast) + print("\n1๏ธโƒฃ Testing with extract_best_match_only=True (FAST)") + start_time = time.time() + + result_fast = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term=search_term, + node_type="Person", + depth=4, + max_results=10, + extract_best_match_only=True + ) + + fast_time = time.time() - start_time + + print(f" โฑ๏ธ Time taken: {fast_time:.2f} seconds") + print(f" ๐Ÿ“Š Total matches found: {result_fast['total_results']}") + print(f" ๐ŸŽฏ Best match: {result_fast['best_match']['node_name']}") + print(f" ๐Ÿ† Best match score: {result_fast['best_match']['score']}") + print(f" ๐Ÿ“ˆ Subgraphs extracted: {len(result_fast['subgraphs'])}") + + if result_fast['subgraphs']: + subgraph = result_fast['subgraphs'][0] + print(f" ๐Ÿ”— Subgraph nodes: {len(subgraph.get('nodes', []))}") + print(f" ๐Ÿ”— Subgraph relationships: {len(subgraph.get('relationships', []))}") + + # Test 2: Extract from all matches (slow) + print("\n2๏ธโƒฃ Testing with extract_best_match_only=False (SLOW)") + start_time = time.time() + + result_slow = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term=search_term, + node_type="Person", + depth=4, + max_results=5, # Limit to 5 to avoid too much delay + extract_best_match_only=False + ) + + slow_time = time.time() - start_time + + print(f" โฑ๏ธ Time taken: {slow_time:.2f} seconds") + print(f" ๐Ÿ“Š Total matches found: {result_slow['total_results']}") + print(f" ๐ŸŽฏ Best match: {result_slow['best_match']['node_name']}") + print(f" ๐Ÿ† Best match score: {result_slow['best_match']['score']}") + print(f" ๐Ÿ“ˆ Subgraphs extracted: {len(result_slow['subgraphs'])}") + + # Performance comparison + print("\n๐Ÿ“Š Performance Comparison:") + print(f" Fast method (best match only): {fast_time:.2f}s") + print(f" Slow method (all matches): {slow_time:.2f}s") + + if slow_time > 0: + speedup = slow_time / fast_time + print(f" ๐Ÿš€ Speedup: {speedup:.1f}x faster") + + # Show all matches found + print("\n๐Ÿ“‹ All matches found:") + for i, match in enumerate(result_fast['all_matches'][:5]): + print(f" {i+1}. {match['node_name']} (score: {match['score']}, method: {match['search_method']})") + + print("\nโœ… Performance test completed!") + return True + + except Exception as e: + print(f"โŒ Test failed with error: {str(e)}") + return False + +if __name__ == "__main__": + success = test_performance_improvement() + sys.exit(0 if success else 1) diff --git a/backend/tests/test_risk_assessment.py b/backend/tests/test_risk_assessment.py new file mode 100644 index 000000000..4a154243c --- /dev/null +++ b/backend/tests/test_risk_assessment.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 +""" +Test script to demonstrate risk assessment functionality +""" + +import os +import sys +import json +from dotenv import load_dotenv + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.risk_assessment import analyze_risk + +load_dotenv() + +def test_risk_assessment(): + """Test the risk assessment functionality""" + + # Get connection details from environment or use defaults + uri = os.getenv('NEO4J_URI', 'neo4j+ssc://224c5da6.databases.neo4j.io') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', '') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + if not password: + print("โŒ NEO4J_PASSWORD environment variable not set") + return False + + try: + print("๐Ÿ” Testing risk assessment functionality...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + # Define risk indicators for testing + risk_indicators = { + "Foreign State Influence": 80, + "Dual-Use Technology Exposure": 70, + "Compliance with Canadian Research Security Policies": 60, + "International Collaboration Patterns": 50, + "Funding Sources Transparency": 40 + } + + # Test cases + test_cases = [ + { + "entity_name": "Bill Gates", + "entity_type": "Person", + "description": "Individual person assessment" + }, + { + "entity_name": "Microsoft", + "entity_type": "Organization", + "description": "Organization assessment" + }, + { + "entity_name": "OpenAI", + "entity_type": "Organization", + "description": "AI company assessment" + } + ] + + print(f"\n๐Ÿ“‹ Testing {len(test_cases)} risk assessment scenarios...") + + for i, test_case in enumerate(test_cases, 1): + print(f"\n{i}. Testing: '{test_case['entity_name']}' ({test_case['entity_type']})") + print(f" Description: {test_case['description']}") + + try: + # Perform risk assessment + result = analyze_risk( + uri=uri, + username=username, + password=password, + database=database, + entity_name=test_case['entity_name'], + entity_type=test_case['entity_type'], + risk_indicators=risk_indicators, + depth=4, + max_results=10 + ) + + # Check if entity was found + if 'error' in result: + print(f" โŒ {result['error']}") + continue + + # Display results + print(f" โœ… Risk assessment completed") + print(f" ๐Ÿ“Š Analysis metadata:") + metadata = result.get('analysis_metadata', {}) + print(f" Chunks analyzed: {metadata.get('chunks_analyzed', 0)}") + print(f" Subgraph nodes: {metadata.get('subgraph_nodes', 0)}") + print(f" Subgraph relationships: {metadata.get('subgraph_relationships', 0)}") + print(f" Search method: {metadata.get('search_method', 'unknown')}") + print(f" Best match score: {metadata.get('best_match_score', 'N/A')}") + + # Display risk assessment results + calculation = result.get('calculation', {}) + final_assessment = result.get('finalAssessment', {}) + + print(f" ๐ŸŽฏ Risk assessment results:") + print(f" Overall score: {calculation.get('overallScore', 'N/A')}") + print(f" Traffic light: {final_assessment.get('trafficLight', 'N/A')}") + print(f" Overall explanation: {final_assessment.get('overallExplanation', 'N/A')}") + + # Display individual risk indicators + risk_assessments = result.get('riskAssessments', []) + print(f" ๐Ÿ“‹ Individual risk indicators:") + for assessment in risk_assessments: + indicator = assessment.get('indicator', 'Unknown') + score = assessment.get('score', 'N/A') + weight = assessment.get('weight', 'N/A') + sources = assessment.get('sources', []) + explanation = assessment.get('explanation', 'N/A') + + print(f" โ€ข {indicator}") + print(f" Score: {score}/5, Weight: {weight}") + print(f" Sources: {sources if sources else ['nil']}") + print(f" Explanation: {explanation[:100]}...") + + # Save detailed results to file + output_file = f"risk_assessment_{test_case['entity_name'].replace(' ', '_')}.json" + with open(output_file, 'w') as f: + json.dump(result, f, indent=2) + print(f" ๐Ÿ’พ Detailed results saved to: {output_file}") + + except Exception as e: + print(f" โŒ Risk assessment failed: {str(e)}") + + print("\nโœ… Risk assessment tests completed!") + return True + + except Exception as e: + print(f"โŒ Test failed with error: {str(e)}") + return False + +def test_api_endpoint(): + """Test the risk assessment API endpoint""" + + print("\n๐ŸŒ Testing API endpoint...") + + # Example curl command + risk_indicators_json = json.dumps({ + "Foreign State Influence": 80, + "Dual-Use Technology Exposure": 70, + "Compliance with Canadian Research Security Policies": 60 + }) + + curl_command = f'''curl -X POST "http://localhost:8000/analyze_risk" \\ + -F "uri=your_neo4j_uri" \\ + -F "userName=your_username" \\ + -F "password=your_password" \\ + -F "database=neo4j" \\ + -F "entity_name=Bill Gates" \\ + -F "entity_type=Person" \\ + -F "risk_indicators='{risk_indicators_json}'" \\ + -F "depth=4" \\ + -F "max_results=10"''' + + print("Example API call:") + print(curl_command) + + print("\n๐Ÿ“ API Parameters:") + print(" โ€ข entity_name: Name of the entity to assess") + print(" โ€ข entity_type: Type of entity (Person, Organization, etc.)") + print(" โ€ข risk_indicators: JSON string of risk indicators and weights") + print(" โ€ข depth: Depth for subgraph extraction (default: 4)") + print(" โ€ข max_results: Maximum search results to consider (default: 10)") + +if __name__ == "__main__": + success = test_risk_assessment() + test_api_endpoint() + sys.exit(0 if success else 1) diff --git a/backend/tests/test_risk_monitor.py b/backend/tests/test_risk_monitor.py new file mode 100644 index 000000000..d8c2c04db --- /dev/null +++ b/backend/tests/test_risk_monitor.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +""" +Test script for Risk Monitoring functionality +""" + +import json +import sys +import os + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +def test_risk_monitoring_imports(): + """Test that all imports work correctly.""" + try: + from src.risk_monitor import perform_risk_monitoring + from src.constants.risk_monitoring_prompts import RISK_MONITORING_PROMPTS, RISK_LEVELS + print("โœ… All imports successful") + return True + except Exception as e: + print(f"โŒ Import failed: {e}") + return False + +def test_constants(): + """Test that constants are properly defined.""" + try: + from src.constants.risk_monitoring_prompts import RISK_MONITORING_PROMPTS, RISK_LEVELS + + # Check prompts + required_prompts = ["NAME_MONITORING", "RISK_ANALYSIS", "RISK_SUMMARY"] + for prompt in required_prompts: + if prompt not in RISK_MONITORING_PROMPTS: + print(f"โŒ Missing prompt: {prompt}") + return False + + # Check risk levels + required_levels = ["LOW", "MEDIUM", "HIGH"] + for level in required_levels: + if level not in RISK_LEVELS: + print(f"โŒ Missing risk level: {level}") + return False + + print("โœ… All constants properly defined") + return True + except Exception as e: + print(f"โŒ Constants test failed: {e}") + return False + +def test_function_signatures(): + """Test that function signatures are correct.""" + try: + from src.risk_monitor import perform_risk_monitoring + + # Check function exists and has correct signature + if not callable(perform_risk_monitoring): + print("โŒ perform_risk_monitoring is not callable") + return False + + print("โœ… Function signatures correct") + return True + except Exception as e: + print(f"โŒ Function signature test failed: {e}") + return False + +def test_sample_data(): + """Test with sample data structures.""" + try: + # Sample monitored names + monitored_names = ["John Doe", "Jane Smith", "Acme Corp"] + + # Sample risk indicators + risk_indicators = [ + "financial_fraud", + "regulatory_violation", + "money_laundering", + "insider_trading" + ] + + # Sample document name + document_name = "sample_document.pdf" + + print("โœ… Sample data structures created:") + print(f" - Monitored names: {monitored_names}") + print(f" - Risk indicators: {risk_indicators}") + print(f" - Document: {document_name}") + + return True + except Exception as e: + print(f"โŒ Sample data test failed: {e}") + return False + +def main(): + """Run all tests.""" + print("๐Ÿงช Testing Risk Monitoring Implementation") + print("=" * 50) + + tests = [ + ("Import Test", test_risk_monitoring_imports), + ("Constants Test", test_constants), + ("Function Signatures Test", test_function_signatures), + ("Sample Data Test", test_sample_data) + ] + + passed = 0 + total = len(tests) + + for test_name, test_func in tests: + print(f"\n๐Ÿ” Running {test_name}...") + if test_func(): + passed += 1 + print(f"โœ… {test_name} PASSED") + else: + print(f"โŒ {test_name} FAILED") + + print("\n" + "=" * 50) + print(f"๐Ÿ“Š Test Results: {passed}/{total} tests passed") + + if passed == total: + print("๐ŸŽ‰ All tests passed! Risk monitoring implementation is ready.") + return True + else: + print("โš ๏ธ Some tests failed. Please check the implementation.") + return False + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/backend/tests/test_search.py b/backend/tests/test_search.py new file mode 100644 index 000000000..93a7b63ae --- /dev/null +++ b/backend/tests/test_search.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +""" +Test script for the search functionality +""" + +import os +import sys +import asyncio +from dotenv import load_dotenv + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graph_query import search_nodes, get_subgraph_from_node, search_and_get_subgraph + +load_dotenv() + +def test_search_functionality(): + """Test the search functionality with sample data""" + + # Get connection details from environment or use defaults + uri = os.getenv('NEO4J_URI', 'neo4j+ssc://224c5da6.databases.neo4j.io') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', '') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + if not password: + print("โŒ NEO4J_PASSWORD environment variable not set") + return False + + try: + print("๐Ÿ” Testing search functionality...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + # Test 1: Search for nodes + print("\n1. Testing node search...") + search_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term="test", + node_type="Person", + max_results=5 + ) + + print(f"โœ… Search completed successfully") + print(f" Total results: {search_results['total_results']}") + print(f" Nodes found: {len(search_results['nodes'])}") + + if search_results['nodes']: + print(f" Sample node: {search_results['nodes'][0]}") + + # Test 2: Get subgraph from first node + print("\n2. Testing subgraph extraction...") + first_node = search_results['nodes'][0] + subgraph = get_subgraph_from_node( + uri=uri, + username=username, + password=password, + database=database, + node_id=first_node['element_id'], + depth=2, + max_nodes=100 + ) + + print(f"โœ… Subgraph extraction completed successfully") + print(f" Nodes in subgraph: {len(subgraph['nodes'])}") + print(f" Relationships in subgraph: {len(subgraph['relationships'])}") + + # Test 3: Combined search and subgraph + print("\n3. Testing combined search and subgraph...") + combined_results = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term="test", + node_type="Person", + depth=2, + max_results=3 + ) + + print(f"โœ… Combined search completed successfully") + print(f" Total results: {combined_results['total_results']}") + print(f" Subgraphs extracted: {len(combined_results['subgraphs'])}") + + print("\n๐ŸŽ‰ All tests passed successfully!") + return True + + except Exception as e: + print(f"โŒ Test failed with error: {str(e)}") + return False + +if __name__ == "__main__": + success = test_search_functionality() + sys.exit(0 if success else 1) diff --git a/backend/tests/test_search_method.py b/backend/tests/test_search_method.py new file mode 100644 index 000000000..308e7d3ca --- /dev/null +++ b/backend/tests/test_search_method.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +""" +Test script to verify search method is properly captured. +""" + +import sys +import os +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from src.graph_query import search_and_get_subgraph +import logging + +# Set up logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +def test_search_method(): + """Test that search method is properly captured.""" + + # Connection parameters + uri = "neo4j+ssc://224c5da6.databases.neo4j.io" + username = "neo4j" + password = "" # Add your password here + database = "neo4j" + + if not password: + print("โŒ Please set the password in the script") + return + + print("๐Ÿ” Testing search method capture...") + + try: + # Test search and subgraph extraction + subgraph_data = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term="Bill Gates", + node_type="Person", + depth=4, + max_results=10, + extract_best_match_only=True, + preserve_text=True + ) + + print(f"\n๐Ÿ“Š Search results:") + print(f" Total results: {subgraph_data.get('total_results', 0)}") + + # Check best match information + best_match = subgraph_data.get('best_match', {}) + print(f"\n๐Ÿ† Best match:") + print(f" Node name: {best_match.get('node_name', 'Unknown')}") + print(f" Score: {best_match.get('score', 'N/A')}") + print(f" Search method: {best_match.get('search_method', 'unknown')}") + print(f" Element ID: {best_match.get('element_id', 'Unknown')}") + + # Check all matches + all_matches = subgraph_data.get('all_matches', []) + print(f"\n๐Ÿ“‹ All matches ({len(all_matches)}):") + for i, match in enumerate(all_matches[:3]): # Show first 3 + print(f" {i+1}. {match.get('node_name', 'Unknown')}") + print(f" Score: {match.get('score', 'N/A')}") + print(f" Search method: {match.get('search_method', 'unknown')}") + + # Test the risk assessment metadata + print(f"\n๐Ÿ”ง Testing risk assessment metadata...") + from src.risk_assessment import analyze_risk + + risk_indicators = { + "Foreign State Influence": 80, + "Dual-Use Technology Exposure": 70 + } + + result = analyze_risk( + uri=uri, + username=username, + password=password, + database=database, + entity_name="Bill Gates", + entity_type="Person", + risk_indicators=risk_indicators, + depth=4, + max_results=10 + ) + + if 'error' not in result: + metadata = result.get('analysis_metadata', {}) + print(f"\nโœ… Risk assessment metadata:") + print(f" Search method: {metadata.get('search_method', 'unknown')}") + print(f" Best match score: {metadata.get('best_match_score', 'N/A')}") + print(f" Chunks analyzed: {metadata.get('chunks_analyzed', 0)}") + print(f" Subgraph nodes: {metadata.get('subgraph_nodes', 0)}") + + if metadata.get('search_method') != 'unknown': + print(f" โœ… Search method is now properly captured!") + else: + print(f" โš ๏ธ Search method still shows as 'unknown'") + else: + print(f"โŒ Error in risk assessment: {result['error']}") + + except Exception as e: + print(f"โŒ Error: {str(e)}") + logging.exception("Error in search method test") + +if __name__ == "__main__": + test_search_method() diff --git a/backend/tests/test_source_extraction.py b/backend/tests/test_source_extraction.py new file mode 100644 index 000000000..dbb45a86f --- /dev/null +++ b/backend/tests/test_source_extraction.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +""" +Test script to examine source information in chunks and documents. +""" + +import sys +import os +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from src.graph_query import search_and_get_subgraph +import logging +import json + +# Set up logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +def test_source_extraction(): + """Test source extraction from the database.""" + + # Connection parameters + uri = "neo4j+ssc://224c5da6.databases.neo4j.io" + username = "neo4j" + password = "" # Add your password here + database = "neo4j" + + print("๐Ÿ” Testing source extraction from database...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + try: + # Search for Bill Gates and extract subgraph + subgraph_data = search_and_get_subgraph( + uri=uri, + username=username, + password=password, + database=database, + search_term="Bill Gates", + node_type="Person", + depth=4, + max_results=10, + extract_best_match_only=True, + preserve_text=True + ) + + if not subgraph_data.get('subgraphs'): + print("โŒ No subgraph found") + return + + print(f"\n๐Ÿ“Š Subgraph extracted:") + print(f" Subgraphs: {len(subgraph_data['subgraphs'])}") + + # Analyze nodes in the subgraph + all_nodes = [] + document_nodes = [] + chunk_nodes = [] + + for subgraph in subgraph_data['subgraphs']: + for node in subgraph.get('nodes', []): + all_nodes.append(node) + node_labels = node.get('labels', []) + node_props = node.get('properties', {}) + + # Categorize nodes + if any(label in ['Document', 'File', 'Source'] for label in node_labels): + document_nodes.append({ + 'element_id': node.get('element_id'), + 'labels': node_labels, + 'properties': node_props + }) + elif any(label in ['Chunk', 'DocumentChunk', 'TextChunk'] for label in node_labels): + chunk_nodes.append({ + 'element_id': node.get('element_id'), + 'labels': node_labels, + 'properties': node_props + }) + + print(f" Total nodes: {len(all_nodes)}") + print(f" Document nodes: {len(document_nodes)}") + print(f" Chunk nodes: {len(chunk_nodes)}") + + # Analyze document nodes + print(f"\n๐Ÿ“„ Document nodes found:") + for i, doc in enumerate(document_nodes[:5]): # Show first 5 + print(f"\n Document {i+1}:") + print(f" Element ID: {doc['element_id']}") + print(f" Labels: {doc['labels']}") + print(f" Properties: {list(doc['properties'].keys())}") + + # Show key properties + for key in ['id', 'name', 'url', 'source', 'document_id', 'type']: + if key in doc['properties']: + print(f" {key}: {doc['properties'][key]}") + + # Analyze chunk nodes + print(f"\n๐Ÿ“ Chunk nodes found:") + for i, chunk in enumerate(chunk_nodes[:5]): # Show first 5 + print(f"\n Chunk {i+1}:") + print(f" Element ID: {chunk['element_id']}") + print(f" Labels: {chunk['labels']}") + print(f" Properties: {list(chunk['properties'].keys())}") + + # Show key properties + for key in ['id', 'text', 'content', 'source', 'document_id', 'doc_id', 'url']: + if key in chunk['properties']: + value = chunk['properties'][key] + if key in ['text', 'content'] and len(str(value)) > 100: + value = str(value)[:100] + "..." + print(f" {key}: {value}") + + # Test the enhanced chunk extraction + print(f"\n๐Ÿ”ง Testing enhanced chunk extraction...") + from src.risk_assessment import extract_chunks_from_subgraph + + chunks = extract_chunks_from_subgraph(subgraph_data) + + print(f"\n๐Ÿ“‹ Extracted {len(chunks)} chunks:") + for i, chunk in enumerate(chunks): + print(f"\n Chunk {i+1}:") + print(f" ID: {chunk['chunk_id']}") + print(f" Document: {chunk['document_name'] or chunk['document_id']}") + print(f" Source: {chunk['source']}") + print(f" Text length: {len(chunk['text'])} characters") + print(f" Text preview: {chunk['text'][:100]}...") + + # Save detailed results + results = { + 'subgraph_summary': { + 'total_nodes': len(all_nodes), + 'document_nodes': len(document_nodes), + 'chunk_nodes': len(chunk_nodes) + }, + 'document_nodes': document_nodes, + 'chunk_nodes': chunk_nodes, + 'extracted_chunks': chunks + } + + with open('source_extraction_results.json', 'w') as f: + json.dump(results, f, indent=2, default=str) + + print(f"\n๐Ÿ’พ Detailed results saved to: source_extraction_results.json") + + except Exception as e: + print(f"โŒ Error: {str(e)}") + logging.exception("Error in source extraction test") + +if __name__ == "__main__": + test_source_extraction() diff --git a/backend/tests/test_url_copying.py b/backend/tests/test_url_copying.py new file mode 100644 index 000000000..870404037 --- /dev/null +++ b/backend/tests/test_url_copying.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +""" +Test URL Copying to Chunk Nodes + +This script tests whether URLs are now being properly copied from Document nodes +to Chunk nodes during the chunk creation process. +""" + +import os +import sys +import logging +from dotenv import load_dotenv + +# Add src to path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graphDB_dataAccess import graphDBdataAccess +from src.shared.common_fn import create_graph_database_connection + +# Configure logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def test_url_copying(): + """ + Test whether URLs are being copied to chunk nodes. + """ + + # Load environment variables + load_dotenv() + + # Get database connection details + uri = os.getenv('NEO4J_URI', 'bolt://localhost:7687') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', 'password') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + try: + # Create database connection + graph = create_graph_database_connection(uri, username, password, database) + graph_db_access = graphDBdataAccess(graph) + + print("๐Ÿ” TESTING URL COPYING TO CHUNK NODES") + print("=" * 60) + + # Test 1: Check Document nodes with URLs + print("\n๐Ÿ“‹ TEST 1: Document Nodes with URLs") + print("-" * 40) + + doc_query = """ + MATCH (d:Document) + WHERE d.url IS NOT NULL + RETURN d.fileName as fileName, d.url as url, d.fileSource as source + LIMIT 5 + """ + + doc_results = graph.query(doc_query) + if doc_results: + print("โœ… Found Document nodes with URLs:") + for record in doc_results: + print(f" ๐Ÿ“„ {record['fileName']}") + print(f" URL: {record['url']}") + print(f" Source: {record['source']}") + print() + else: + print("โŒ No Document nodes with URLs found") + + # Test 2: Check Chunk nodes with URLs + print("\n๐Ÿ“‹ TEST 2: Chunk Nodes with URLs") + print("-" * 40) + + chunk_query = """ + MATCH (c:Chunk) + WHERE c.url IS NOT NULL + RETURN c.fileName as fileName, c.url as url, c.fileSource as source, c.position as position + LIMIT 10 + """ + + chunk_results = graph.query(chunk_query) + if chunk_results: + print("โœ… Found Chunk nodes with URLs:") + for record in chunk_results: + print(f" ๐Ÿ“„ {record['fileName']} (Position: {record['position']})") + print(f" URL: {record['url']}") + print(f" Source: {record['source']}") + print() + else: + print("โŒ No Chunk nodes with URLs found") + print(" This means the URL copying fix hasn't been applied to existing data") + + # Test 3: Check Document-Chunk relationships + print("\n๐Ÿ“‹ TEST 3: Document-Chunk Relationships") + print("-" * 40) + + rel_query = """ + MATCH (c:Chunk)-[:PART_OF]->(d:Document) + WHERE d.url IS NOT NULL + RETURN d.fileName as docName, d.url as docUrl, + c.fileName as chunkName, c.url as chunkUrl, + c.fileSource as chunkSource + LIMIT 5 + """ + + rel_results = graph.query(rel_query) + if rel_results: + print("โœ… Document-Chunk relationships:") + for record in rel_results: + print(f" ๐Ÿ“„ Document: {record['docName']}") + print(f" Doc URL: {record['docUrl']}") + print(f" Chunk: {record['chunkName']}") + print(f" Chunk URL: {record['chunkUrl']}") + print(f" Chunk Source: {record['chunkSource']}") + print() + else: + print("โŒ No Document-Chunk relationships found") + + # Test 4: Check for chunks without URLs + print("\n๐Ÿ“‹ TEST 4: Chunks Without URLs") + print("-" * 40) + + no_url_query = """ + MATCH (c:Chunk) + WHERE c.url IS NULL + RETURN c.fileName as fileName, c.fileSource as source, c.position as position + LIMIT 5 + """ + + no_url_results = graph.query(no_url_query) + if no_url_results: + print("โš ๏ธ Found Chunk nodes WITHOUT URLs:") + for record in no_url_results: + print(f" ๐Ÿ“„ {record['fileName']} (Position: {record['position']})") + print(f" Source: {record['source']}") + print() + print(" These are likely from before the URL copying fix") + else: + print("โœ… All Chunk nodes have URLs!") + + # Test 5: Check local file references + print("\n๐Ÿ“‹ TEST 5: Local File References") + print("-" * 40) + + local_query = """ + MATCH (c:Chunk) + WHERE c.url STARTS WITH 'local://' + RETURN c.fileName as fileName, c.url as url, c.fileSource as source + LIMIT 5 + """ + + local_results = graph.query(local_query) + if local_results: + print("โœ… Found local file references:") + for record in local_results: + print(f" ๐Ÿ“„ {record['fileName']}") + print(f" URL: {record['url']}") + print(f" Source: {record['source']}") + print() + else: + print("โ„น๏ธ No local file references found") + + # Summary + print("\n๐Ÿ“Š SUMMARY") + print("=" * 60) + + # Count documents with URLs + doc_count_query = "MATCH (d:Document) WHERE d.url IS NOT NULL RETURN count(d) as count" + doc_count = graph.query(doc_count_query)[0]['count'] + + # Count chunks with URLs + chunk_count_query = "MATCH (c:Chunk) WHERE c.url IS NOT NULL RETURN count(c) as count" + chunk_count = graph.query(chunk_count_query)[0]['count'] + + # Count total chunks + total_chunks_query = "MATCH (c:Chunk) RETURN count(c) as count" + total_chunks = graph.query(total_chunks_query)[0]['count'] + + print(f"๐Ÿ“„ Documents with URLs: {doc_count}") + print(f"๐Ÿ“„ Chunks with URLs: {chunk_count}/{total_chunks} ({chunk_count/total_chunks*100:.1f}%)") + + if chunk_count > 0: + print("โœ… URL copying is working for new chunks!") + else: + print("โŒ URL copying not working - check the implementation") + + if chunk_count < total_chunks: + print("โ„น๏ธ Some chunks don't have URLs (likely from before the fix)") + + except Exception as e: + logger.error(f"Error testing URL copying: {str(e)}") + print(f"โŒ Error: {str(e)}") + finally: + if 'graph' in locals(): + graph.close() + +if __name__ == "__main__": + test_url_copying() diff --git a/backend/tests/test_vector_search.py b/backend/tests/test_vector_search.py new file mode 100644 index 000000000..cde66c635 --- /dev/null +++ b/backend/tests/test_vector_search.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +""" +Test script for the enhanced vector search functionality +""" + +import os +import sys +import asyncio +from dotenv import load_dotenv + +# Add the src directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from src.graph_query import search_nodes, check_vector_availability + +load_dotenv() + +def test_vector_search_functionality(): + """Test the enhanced vector search functionality""" + + # Get connection details from environment or use defaults + uri = os.getenv('NEO4J_URI', 'neo4j+ssc://224c5da6.databases.neo4j.io') + username = os.getenv('NEO4J_USERNAME', 'neo4j') + password = os.getenv('NEO4J_PASSWORD', '') + database = os.getenv('NEO4J_DATABASE', 'neo4j') + + if not password: + print("โŒ NEO4J_PASSWORD environment variable not set") + return False + + try: + print("๐Ÿ” Testing enhanced vector search functionality...") + print(f"Connecting to: {uri}") + print(f"Database: {database}") + print(f"Username: {username}") + + # Test 1: Check vector availability for different node types + print("\n1. Checking vector availability...") + from src.graph_query import get_graphDB_driver + + driver = get_graphDB_driver(uri, username, password, database) + + node_types_to_check = ["Person", "Organization", "Location", "Technology"] + + for node_type in node_types_to_check: + vector_info = check_vector_availability(driver, node_type) + print(f" {node_type}: {vector_info['has_embeddings']} " + f"({vector_info['nodes_with_embeddings']}/{vector_info['total_nodes']} nodes, " + f"{vector_info['embedding_coverage']:.1%} coverage)") + + driver.close() + + # Test 2: Search with vector preference (default) + print("\n2. Testing search with vector preference...") + search_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term="software engineer", + node_type="Person", + max_results=5, + prefer_vector=True + ) + + print(f"โœ… Search completed successfully") + print(f" Search method used: {search_results['search_method']}") + print(f" Vector available: {search_results['search_metadata']['vector_available']}") + print(f" Embedding coverage: {search_results['search_metadata']['embedding_coverage']:.1%}") + print(f" Total results: {search_results['total_results']}") + print(f" Nodes found: {len(search_results['nodes'])}") + + if search_results['nodes']: + print(f" Sample node: {search_results['nodes'][0]}") + + # Show similarity scores if using vector search + if search_results['search_method'] == 'vector_similarity': + print(" Similarity scores:") + for i, node in enumerate(search_results['nodes'][:3]): + print(f" {i+1}. {node.get('properties', {}).get('id', 'Unknown')}: {node.get('similarity_score', 'N/A')}") + + # Test 3: Search with text preference + print("\n3. Testing search with text preference...") + text_search_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term="John", + node_type="Person", + max_results=5, + prefer_vector=False + ) + + print(f"โœ… Text search completed successfully") + print(f" Search method used: {text_search_results['search_method']}") + print(f" Total results: {text_search_results['total_results']}") + + # Test 4: Search for organizations + print("\n4. Testing organization search...") + org_search_results = search_nodes( + uri=uri, + username=username, + password=password, + database=database, + search_term="technology company", + node_type="Organization", + max_results=3, + prefer_vector=True + ) + + print(f"โœ… Organization search completed successfully") + print(f" Search method used: {org_search_results['search_method']}") + print(f" Total results: {org_search_results['total_results']}") + + if org_search_results['nodes']: + print(" Organizations found:") + for i, node in enumerate(org_search_results['nodes']): + org_name = node.get('properties', {}).get('id', 'Unknown') + similarity = node.get('similarity_score', 'N/A') + print(f" {i+1}. {org_name} (similarity: {similarity})") + + print("\n๐ŸŽ‰ All tests passed successfully!") + return True + + except Exception as e: + print(f"โŒ Test failed with error: {str(e)}") + return False + +if __name__ == "__main__": + success = test_vector_search_functionality() + sys.exit(0 if success else 1) diff --git a/docker-compose.yml b/docker-compose.yml index 4b166f490..ac43f0105 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,13 +26,13 @@ services: - NUMBER_OF_CHUNKS_TO_COMBINE=${NUMBER_OF_CHUNKS_TO_COMBINE-6} - ENTITY_EMBEDDING=${ENTITY_EMBEDDING-False} - GCS_FILE_CACHE=${GCS_FILE_CACHE-False} -# - LLM_MODEL_CONFIG_anthropic_claude_35_sonnet=${LLM_MODEL_CONFIG_anthropic_claude_35_sonnet-} -# - LLM_MODEL_CONFIG_fireworks_llama_v3_70b=${LLM_MODEL_CONFIG_fireworks_llama_v3_70b-} -# - LLM_MODEL_CONFIG_azure_ai_gpt_4o=${LLM_MODEL_CONFIG_azure_ai_gpt_4o-} -# - LLM_MODEL_CONFIG_azure_ai_gpt_35=${LLM_MODEL_CONFIG_azure_ai_gpt_35-} -# - LLM_MODEL_CONFIG_groq_llama3_70b=${LLM_MODEL_CONFIG_groq_llama3_70b-} -# - LLM_MODEL_CONFIG_bedrock_claude_3_5_sonnet=${LLM_MODEL_CONFIG_bedrock_claude_3_5_sonnet-} -# - LLM_MODEL_CONFIG_fireworks_qwen_72b=${LLM_MODEL_CONFIG_fireworks_qwen_72b-} + # - LLM_MODEL_CONFIG_anthropic_claude_35_sonnet=${LLM_MODEL_CONFIG_anthropic_claude_35_sonnet-} + # - LLM_MODEL_CONFIG_fireworks_llama_v3_70b=${LLM_MODEL_CONFIG_fireworks_llama_v3_70b-} + # - LLM_MODEL_CONFIG_azure_ai_gpt_4o=${LLM_MODEL_CONFIG_azure_ai_gpt_4o-} + # - LLM_MODEL_CONFIG_azure_ai_gpt_35=${LLM_MODEL_CONFIG_azure_ai_gpt_35-} + # - LLM_MODEL_CONFIG_groq_llama3_70b=${LLM_MODEL_CONFIG_groq_llama3_70b-} + # - LLM_MODEL_CONFIG_bedrock_claude_3_5_sonnet=${LLM_MODEL_CONFIG_bedrock_claude_3_5_sonnet-} + # - LLM_MODEL_CONFIG_fireworks_qwen_72b=${LLM_MODEL_CONFIG_fireworks_qwen_72b-} - LLM_MODEL_CONFIG_ollama_llama3=${LLM_MODEL_CONFIG_ollama_llama3-} container_name: backend extra_hosts: diff --git a/frontend-graph/.gitignore b/frontend-graph/.gitignore new file mode 100644 index 000000000..bfc677e10 --- /dev/null +++ b/frontend-graph/.gitignore @@ -0,0 +1,133 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* +package-lock.json + +docs/build \ No newline at end of file diff --git a/frontend-graph/README.md b/frontend-graph/README.md new file mode 100644 index 000000000..118ced3df --- /dev/null +++ b/frontend-graph/README.md @@ -0,0 +1,56 @@ +# Frontend Graph + +A standalone React application focused on graph visualization components using Neo4j NVL (Neo4j Visualization Library) and NDL (Neo4j Design Library). + +## Getting Started + +### Prerequisites + +- Node.js 18+ +- Yarn + +### Installation + +```bash +# Install dependencies +yarn install + +# Start development server +yarn dev + +# Build for production +yarn build + +# Preview production build +yarn preview +``` + +## Usage + +The `GraphViewer` component serves as the main entry point for graph visualization. It provides: + +- A clean interface to open graph visualizations +- Integration with Neo4j NVL for interactive graphs +- Zoom controls and graph navigation +- Support for custom node and relationship data + +## Integration + +This frontend can be integrated with your backend API by: + +1. Connecting to your Neo4j database +2. Fetching graph data (nodes and relationships) +3. Passing the data to the `GraphViewModal` component +4. Customizing the color scheme and styling as needed + +## Development + +The project uses: + +- **ESLint** for code linting +- **Prettier** for code formatting +- **TypeScript** for type checking + +Run `yarn lint` to check for linting issues and `yarn format` to format code. + +## License diff --git a/frontend-graph/index.html b/frontend-graph/index.html new file mode 100644 index 000000000..9454cb1fa --- /dev/null +++ b/frontend-graph/index.html @@ -0,0 +1,13 @@ + + + + + + + Graph Visualization + + +
+ + + \ No newline at end of file diff --git a/frontend-graph/package.json b/frontend-graph/package.json new file mode 100644 index 000000000..2d19397ac --- /dev/null +++ b/frontend-graph/package.json @@ -0,0 +1,54 @@ +{ + "name": "frontend-graph", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite --host 0.0.0.0", + "build": "tsc && vite build", + "format": "prettier --write \"**/*.{ts,tsx}\"", + "lint": "eslint --ext .ts --ext .tsx . --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/styled": "^11.14.0", + "@mui/material": "^5.15.10", + "@mui/styled-engine": "^7.1.0", + "@neo4j-devtools/word-color": "^0.0.8", + "@neo4j-ndl/base": "^3.2.9", + "@neo4j-ndl/react": "^3.2.18", + "@neo4j-nvl/base": "^0.3.6", + "@neo4j-nvl/react": "^0.3.8", + "@tanstack/react-table": "^8.20.5", + "@types/uuid": "^10.0.0", + "autoprefixer": "^10.4.21", + "axios": "^1.8.4", + "clsx": "^2.1.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-icons": "^5.5.0", + "react-markdown": "^10.1.0", + "react-router": "^6.23.1", + "react-router-dom": "^6.23.1", + "rehype-raw": "^7.0.0", + "remark-gfm": "^4.0.1", + "uuid": "^11.1.0" + }, + "devDependencies": { + "@types/node": "^22.13.10", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitejs/plugin-react": "^4.5.0", + "eslint": "^8.45.0", + "eslint-config-prettier": "^10.1.1", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.20", + "postcss": "^8.5.6", + "prettier": "^3.5.3", + "tailwindcss": "^3.4.0", + "typescript": "^5.7.3", + "vite": "^4.5.3" + } +} diff --git a/frontend-graph/postcss.config.js b/frontend-graph/postcss.config.js new file mode 100644 index 000000000..2aa7205d4 --- /dev/null +++ b/frontend-graph/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/frontend-graph/src/App.css b/frontend-graph/src/App.css new file mode 100644 index 000000000..dd5727248 --- /dev/null +++ b/frontend-graph/src/App.css @@ -0,0 +1,84 @@ +.App { + text-align: center; + height: 100vh; + width: 100vw; +} + +.ndl-modal-root { + z-index: 10000 !important; +} + +.chatbot-deleteLoader { + position: absolute; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + z-index: 111; + opacity: 0.8; + background-color: rgb(201 201 201 / 40%); +} + +.legend_div { + flex-wrap: wrap; + flex: 1; + padding: 15px; + background-color: rgb(var(--theme-palette-neutral-bg-weak)); + scrollbar-width: thin; + max-height: 100%; + overflow-y: auto; + height: 100%; + z-index: 1; + box-shadow: -2px 0px 6px rgb(var(--theme-palette-neutral-bg-strong)); +} + +.legend { + display: inline-block; + min-width: 0px; + cursor: pointer; + border-radius: 12px; + padding: 5px 8px; + font-size: var(--font-size-label); + font-weight: var(--font-weight-bold); + letter-spacing: 0; + line-height: var(--line-height-label); + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; + background-color: rgb(var(--theme-palette-neutral-bg-strong)); + color: rgb(var(--theme-palette-neutral-text-strong)); + border: 1px solid rgb(var(--theme-palette-neutral-border-strong)); +} + +.legend:hover { + background-color: rgb(var(--theme-palette-neutral-bg-strong)); + color: rgb(var(--theme-palette-neutral-text-strong)); + border-color: rgb(var(--theme-palette-neutral-border-strong)); +} + +.legend.selected { + background-color: rgb(var(--theme-palette-primary-bg-strong)); + color: rgb(var(--theme-palette-primary-text-strong)); + border-color: rgb(var(--theme-palette-primary-border-strong)); +} + +.popup { + position: fixed; + z-index: 1000; + background-color: white; + border: 1px solid #ccc; + padding: 5px; + box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); + border-radius: 8px; +} + +.iframe-preview { + width: 360px; + height: 215px; + border: none; + border-radius: 8px; +} \ No newline at end of file diff --git a/frontend-graph/src/App.tsx b/frontend-graph/src/App.tsx new file mode 100644 index 000000000..aea6a1009 --- /dev/null +++ b/frontend-graph/src/App.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import { + NeedleThemeProvider, + SpotlightProvider, + Toaster, +} from "@neo4j-ndl/react"; +import GraphViewer from "./components/Graph/GraphViewer"; +import "./App.css"; + +function App() { + return ( + + +
+ +
+ +
+
+ ); +} + +export default App; diff --git a/frontend-graph/src/components/Graph/CheckboxSelection.tsx b/frontend-graph/src/components/Graph/CheckboxSelection.tsx new file mode 100644 index 000000000..bb4ee07c9 --- /dev/null +++ b/frontend-graph/src/components/Graph/CheckboxSelection.tsx @@ -0,0 +1,43 @@ +import { Checkbox } from "@neo4j-ndl/react"; +import React from "react"; +import { CheckboxSectionProps } from "../../types"; +import { graphLabels } from "../../utils/Constants"; + +const CheckboxSelection: React.FC = ({ + graphType, + loading, + handleChange, + isCommunity, + isDocChunk, + isEntity, +}) => ( +
+
+ {isDocChunk && ( + handleChange("DocumentChunk")} + /> + )} + {isEntity && ( + handleChange("Entities")} + /> + )} + {isCommunity && ( + handleChange("Communities")} + /> + )} +
+
+); +export default CheckboxSelection; diff --git a/frontend-graph/src/components/Graph/EmbeddedGraphView.tsx b/frontend-graph/src/components/Graph/EmbeddedGraphView.tsx new file mode 100644 index 000000000..d1ead556a --- /dev/null +++ b/frontend-graph/src/components/Graph/EmbeddedGraphView.tsx @@ -0,0 +1,780 @@ +import { + Banner, + Flex, + IconButtonArray, + LoadingSpinner, + useDebounceValue, +} from "@neo4j-ndl/react"; +import { useEffect, useMemo, useRef, useState } from "react"; +import { + BasicNode, + BasicRelationship, + EntityType, + ExtendedNode, + ExtendedRelationship, + GraphType, + OptionType, + Scheme, +} from "../../types"; +import { InteractiveNvlWrapper } from "@neo4j-nvl/react"; +import NVL from "@neo4j-nvl/base"; +import type { Node, Relationship } from "@neo4j-nvl/base"; +import { + ArrowPathIconOutline, + FitToScreenIcon, + InformationCircleIconOutline, + MagnifyingGlassMinusIconOutline, + MagnifyingGlassPlusIconOutline, + ExploreIcon, +} from "@neo4j-ndl/react/icons"; +import { IconButtonWithToolTip } from "../UI/IconButtonToolTip"; +import { + filterData, + getCheckboxConditions, + graphTypeFromNodes, + processGraphData, + extractGraphSchemaFromRawData, +} from "../../utils/Utils"; +import { graphLabels, nvlOptions, queryMap } from "../../utils/Constants"; +import CheckboxSelection from "./CheckboxSelection"; +import ResultOverview from "./ResultOverview"; +import { ResizePanelDetails } from "./ResizePanel"; +import GraphPropertiesPanel from "./GraphPropertiesPanel"; + +interface EmbeddedGraphViewProps { + nodeValues: ExtendedNode[]; + relationshipValues: ExtendedRelationship[]; + viewPoint?: string; +} + +const EmbeddedGraphView: React.FC = ({ + nodeValues, + relationshipValues, + viewPoint = "chatInfoView", +}) => { + const nvlRef = useRef(null); + const [node, setNode] = useState([]); + const [relationship, setRelationship] = useState([]); + const [allNodes, setAllNodes] = useState([]); + const [allRelationships, setAllRelationships] = useState([]); + const [loading, setLoading] = useState(false); + const [status, setStatus] = useState<"unknown" | "success" | "danger">( + "unknown" + ); + const [statusMessage, setStatusMessage] = useState(""); + const [scheme, setScheme] = useState({}); + const [newScheme, setNewScheme] = useState({}); + const [searchQuery, setSearchQuery] = useState(""); + const [debouncedQuery] = useDebounceValue(searchQuery, 300); + const [graphType, setGraphType] = useState([]); + const [disableRefresh, setDisableRefresh] = useState(false); + const [selected, setSelected] = useState< + { type: EntityType; id: string } | undefined + >(undefined); + const [mode, setMode] = useState(false); + const graphQueryAbortControllerRef = useRef(); + const [openGraphView, setOpenGraphView] = useState(false); + const [schemaNodes, setSchemaNodes] = useState([]); + const [schemaRels, setSchemaRels] = useState([]); + const [viewCheck, setViewcheck] = useState("enhancement"); + const [focusedNodeId, setFocusedNodeId] = useState(null); + const [showOnlyConnected, setShowOnlyConnected] = useState(false); + const [minDegree, setMinDegree] = useState(0); + const [showSchemaView, setShowSchemaView] = useState(false); + const [schemaData, setSchemaData] = useState<{ + nodeLabels: string[]; + relationshipTypes: string[]; + }>({ nodeLabels: [], relationshipTypes: [] }); + + const graphQuery: string = + graphType.includes("DocumentChunk") && graphType.includes("Entities") + ? queryMap.DocChunkEntities + : graphType.includes("DocumentChunk") + ? queryMap.DocChunks + : graphType.includes("Entities") + ? queryMap.Entities + : ""; + + // fit graph to original position + const handleZoomToFit = () => { + if (nvlRef.current && allNodes.length > 0) { + nvlRef.current?.fit( + allNodes.map((node) => node.id), + {} + ); + } + }; + + // Initialize graph when component mounts or data changes + useEffect(() => { + if (nodeValues.length > 0 || relationshipValues.length > 0) { + setLoading(true); + + try { + const graphTypes = graphTypeFromNodes(nodeValues); + setGraphType(graphTypes); + + const processedData = processGraphData(nodeValues, relationshipValues); + setAllNodes(processedData.finalNodes); + setAllRelationships(processedData.finalRels); + + // Initialize with all data + setNode(processedData.finalNodes); + setRelationship(processedData.finalRels); + + // Set schema from processed data + setScheme(processedData.schemeVal); + setNewScheme(processedData.schemeVal); + + setStatus("success"); + setStatusMessage("Graph loaded successfully"); + + // Fit to screen after a short delay to ensure the graph is rendered + setTimeout(() => { + handleZoomToFit(); + }, 100); + } catch (error) { + console.error("Error processing graph data:", error); + setStatus("danger"); + setStatusMessage("Error processing graph data"); + } finally { + setLoading(false); + } + } else { + // Reset state when no data + setNode([]); + setRelationship([]); + setAllNodes([]); + setAllRelationships([]); + setGraphType([]); + setScheme({}); + setNewScheme({}); + setStatus("unknown"); + setStatusMessage(""); + } + }, [nodeValues, relationshipValues]); + + // Filter data based on search query + useEffect(() => { + if (debouncedQuery && allNodes.length > 0) { + const filteredData = filterData( + graphType, + allNodes, + allRelationships, + scheme + ); + setNode(filteredData.filteredNodes); + setRelationship(filteredData.filteredRelations); + } else if (allNodes.length > 0) { + setNode(allNodes); + setRelationship(allRelationships); + } + }, [debouncedQuery, allNodes, allRelationships, graphType, scheme]); + + // Apply filtering when graphType changes + useEffect(() => { + if (allNodes.length > 0 && graphType.length > 0) { + let filteredData = filterData( + graphType, + allNodes, + allRelationships, + scheme + ); + + // Apply degree filtering + const degreeFiltered = filterByDegree( + filteredData.filteredNodes, + filteredData.filteredRelations, + minDegree + ); + + // Apply neighborhood focus if enabled + let finalData = degreeFiltered; + if (focusedNodeId && showOnlyConnected) { + finalData = focusOnNeighborhood( + focusedNodeId, + degreeFiltered.nodes, + degreeFiltered.relationships + ); + } + + setNode(finalData.nodes); + setRelationship(finalData.relationships); + } else if (allNodes.length > 0 && graphType.length === 0) { + // If no graph types selected, show all nodes but apply other filters + let filteredData = { nodes: allNodes, relationships: allRelationships }; + + // Apply degree filtering + filteredData = filterByDegree( + filteredData.nodes, + filteredData.relationships, + minDegree + ); + + // Apply neighborhood focus if enabled + if (focusedNodeId && showOnlyConnected) { + filteredData = focusOnNeighborhood( + focusedNodeId, + filteredData.nodes, + filteredData.relationships + ); + } + + setNode(filteredData.nodes); + setRelationship(filteredData.relationships); + } + }, [ + graphType, + allNodes, + allRelationships, + scheme, + minDegree, + focusedNodeId, + showOnlyConnected, + ]); + + const mouseEventCallbacks = useMemo( + () => ({ + onNodeClick: (node: Node) => { + setSelected({ type: "node", id: node.id }); + setFocusedNodeId(node.id); + }, + onRelationshipClick: (relationship: Relationship) => { + setSelected({ type: "relationship", id: relationship.id }); + }, + onCanvasClick: () => { + setSelected(undefined); + setFocusedNodeId(null); + }, + onPan: true, + onZoom: true, + onDrag: true, + }), + [] + ); + + const nvlCallbacks = useMemo( + () => ({ + onLayoutComputing(isComputing: boolean) { + setDisableRefresh(isComputing); + }, + }), + [] + ); + + const handleZoomIn = () => { + nvlRef.current?.setZoom(nvlRef.current.getScale() * 1.3); + }; + + const handleZoomOut = () => { + nvlRef.current?.setZoom(nvlRef.current.getScale() * 0.7); + }; + + const handleRefresh = () => { + if (allNodes.length > 0) { + setNode([...allNodes]); + setRelationship([...allRelationships]); + } + }; + + const handleCheckboxChange = (graph: GraphType) => { + const updatedGraphType = graphType.includes(graph) + ? graphType.filter((type) => type !== graph) + : [...graphType, graph]; + setGraphType(updatedGraphType); + }; + + // Filter nodes by degree (number of connections) + const filterByDegree = ( + nodes: ExtendedNode[], + relationships: ExtendedRelationship[], + minDegree: number + ) => { + if (minDegree === 0) return { nodes, relationships }; + + // Calculate degree for each node + const nodeDegree: { [key: string]: number } = {}; + relationships.forEach((rel) => { + nodeDegree[rel.from] = (nodeDegree[rel.from] || 0) + 1; + nodeDegree[rel.to] = (nodeDegree[rel.to] || 0) + 1; + }); + + // Filter nodes with degree >= minDegree + const filteredNodes = nodes.filter( + (node) => (nodeDegree[node.id] || 0) >= minDegree + ); + const filteredNodeIds = new Set(filteredNodes.map((n) => n.id)); + + // Filter relationships between filtered nodes + const filteredRelationships = relationships.filter( + (rel) => filteredNodeIds.has(rel.from) && filteredNodeIds.has(rel.to) + ); + + return { nodes: filteredNodes, relationships: filteredRelationships }; + }; + + // Focus on neighborhood of a specific node + const focusOnNeighborhood = ( + nodeId: string, + nodes: ExtendedNode[], + relationships: ExtendedRelationship[] + ) => { + if (!showOnlyConnected) return { nodes, relationships }; + + // Find all nodes directly connected to the focused node + const connectedNodeIds = new Set([nodeId]); + relationships.forEach((rel) => { + if (rel.from === nodeId) connectedNodeIds.add(rel.to); + if (rel.to === nodeId) connectedNodeIds.add(rel.from); + }); + + // Filter nodes to only show connected ones + const filteredNodes = nodes.filter((node) => connectedNodeIds.has(node.id)); + + // Filter relationships between connected nodes + const filteredRelationships = relationships.filter( + (rel) => connectedNodeIds.has(rel.from) && connectedNodeIds.has(rel.to) + ); + + return { nodes: filteredNodes, relationships: filteredRelationships }; + }; + + const handleSchemaView = async (rawNodes: any[], rawRelationships: any[]) => { + // Extract unique node labels and relationship types + const nodeLabels = new Set(); + const relationshipTypes = new Set(); + + rawNodes.forEach((node) => { + if (node.labels) { + node.labels.forEach((label: string) => nodeLabels.add(label)); + } + }); + + rawRelationships.forEach((rel) => { + if (rel.type) { + relationshipTypes.add(rel.type); + } + }); + + setSchemaData({ + nodeLabels: Array.from(nodeLabels).sort(), + relationshipTypes: Array.from(relationshipTypes).sort(), + }); + setShowSchemaView(true); + }; + + const selectedItem = useMemo(() => { + if (!selected) return undefined; + + if (selected.type === "node") { + return allNodes.find((n) => n.id === selected.id); + } else { + return allRelationships.find((r) => r.id === selected.id); + } + }, [selected, allNodes, allRelationships]); + + // Always show checkboxes in embedded view for filtering + const checkBoxView = true; + + const headerTitle = "Graph Visualization"; + + if (nodeValues.length === 0 && relationshipValues.length === 0) { + return ( +
+

Graph Visualization

+
+

+ No graph data available. Please load sample data or connect to your + backend first. +

+
+
+ ); + } + + return ( + <> +
+
+ +
+

{headerTitle}

+ {viewPoint !== graphLabels.chatInfoView && ( +
+ + + + + {graphLabels.chunksInfo} + +
+ )} +
+
+ {/* Focus Controls */} +
+ + setShowOnlyConnected(e.target.checked)} + className="rounded border-gray-300" + /> + + Show only connected + +
+ + {/* Degree Filter */} +
+ + setMinDegree(parseInt(e.target.value) || 0)} + className="w-16 px-2 py-1 border border-gray-300 rounded text-sm" + /> +
+ + {checkBoxView && ( + + )} +
+
+
+ +
+
+ {loading ? ( +
+ +
+ ) : status === "danger" ? ( +
+ +
+ ) : node.length === 0 && + relationship.length === 0 && + graphType.length !== 0 ? ( +
+ +
+ ) : graphType.length === 0 && checkBoxView ? ( +
+ +
+ ) : ( + <> +
+
+ + + handleSchemaView(node, relationship)} + placement="left" + > + + + + + {viewPoint !== "chatInfoView" && ( + + + + )} + + + + + + + + + + +
+
+ + )} +
+ + {selectedItem !== undefined ? ( + + ) : ( + + )} + +
+
+ + {/* Schema View Modal */} + {showSchemaView && ( +
+
+
+
+

+ Graph Schema +

+ +
+

+ Schema extracted from current graph data +

+
+ +
+
+ {/* Node Labels */} +
+

+ + + + Node Labels ({schemaData.nodeLabels.length}) +

+ {schemaData.nodeLabels.length > 0 ? ( +
+ {schemaData.nodeLabels.map((label, index) => ( +
+ + {label} + + + Node Type + +
+ ))} +
+ ) : ( +
+ + + +

No node labels found

+
+ )} +
+ + {/* Relationship Types */} +
+

+ + + + Relationship Types ({schemaData.relationshipTypes.length}) +

+ {schemaData.relationshipTypes.length > 0 ? ( +
+ {schemaData.relationshipTypes.map((type, index) => ( +
+ + {type} + + + Relationship + +
+ ))} +
+ ) : ( +
+ + + +

No relationship types found

+
+ )} +
+
+ + {/* Summary */} +
+
+ Schema Summary +
+
+
+ Total Node Types: + + {schemaData.nodeLabels.length} + +
+
+ + Total Relationship Types: + + + {schemaData.relationshipTypes.length} + +
+
+
+
+ +
+
+ +
+
+
+
+ )} + + ); +}; + +export default EmbeddedGraphView; diff --git a/frontend-graph/src/components/Graph/GraphPropertiesPanel.tsx b/frontend-graph/src/components/Graph/GraphPropertiesPanel.tsx new file mode 100644 index 000000000..760dd62b9 --- /dev/null +++ b/frontend-graph/src/components/Graph/GraphPropertiesPanel.tsx @@ -0,0 +1,116 @@ +import { useMemo } from "react"; +import { ResizePanelDetails } from "./ResizePanel"; +import { + BasicNode, + BasicRelationship, + GraphPropertiesPanelProps, +} from "../../types"; +import { LegendsChip } from "./LegendsChip"; +import GraphPropertiesTable from "./GraphPropertiesTable"; + +const sortAlphabetically = (a: string, b: string) => + a.toLowerCase().localeCompare(b.toLowerCase()); + +const isNode = (item: BasicNode | BasicRelationship): item is BasicNode => { + return "labels" in item && !("from" in item) && !("to" in item); +}; + +const GraphPropertiesPanel = ({ + inspectedItem, + newScheme, +}: GraphPropertiesPanelProps) => { + const inspectedItemType = isNode(inspectedItem) ? "node" : "relationship"; + const filteredProperties = + inspectedItemType === "node" + ? Object.entries((inspectedItem as BasicNode).properties) + .filter( + ([, value]) => + value !== null && value !== undefined && value !== " " + ) + .reduce( + (acc, [key, value]) => { + acc[key] = value; + return acc; + }, + {} as Record + ) + : {}; + const properties = + inspectedItemType === "node" + ? [ + { + key: "", + value: `${(inspectedItem as BasicNode).id}`, + type: "String", + }, + ...Object.keys(filteredProperties).map((key) => { + const value = filteredProperties[key]; + return { key, value }; + }), + ] + : [ + { + key: "", + value: `${(inspectedItem as BasicRelationship).id}`, + type: "String", + }, + { + key: "", + value: `${(inspectedItem as BasicRelationship).from}`, + type: "String", + }, + { + key: "", + value: `${(inspectedItem as BasicRelationship).to}`, + type: "String", + }, + { + key: "", + value: `${(inspectedItem as BasicRelationship).caption ?? ""}`, + type: "String", + }, + ]; + const labelsSorted = useMemo(() => { + if (isNode(inspectedItem)) { + return [...inspectedItem.labels].sort(sortAlphabetically); + } + return []; + }, [inspectedItem]); + + return ( + <> + +
+ {inspectedItemType === "node" + ? "Node details" + : "Relationship details"} +
+
+ +
+ {isNode(inspectedItem) ? ( + labelsSorted.map((label) => ( + + )) + ) : ( + + )} +
+
+ + + + ); +}; + +export default GraphPropertiesPanel; diff --git a/frontend-graph/src/components/Graph/GraphPropertiesTable.tsx b/frontend-graph/src/components/Graph/GraphPropertiesTable.tsx new file mode 100644 index 000000000..0652a22ed --- /dev/null +++ b/frontend-graph/src/components/Graph/GraphPropertiesTable.tsx @@ -0,0 +1,51 @@ +import { GraphLabel, Typography } from "@neo4j-ndl/react"; +import { GraphPropertiesTableProps } from "../../types"; + +const GraphPropertiesTable = ({ + propertiesWithTypes, +}: GraphPropertiesTableProps): JSX.Element => { + return ( +
+
+ + Key + + Value +
+ {propertiesWithTypes + .filter( + ({ value }) => + value !== undefined && + value !== null && + value !== "" && + !Array.isArray(value) + ) + .map(({ key, value }, _) => { + return ( +
+
+ + {key} + +
+
{value}
+
+ ); + })} +
+ ); +}; + +export default GraphPropertiesTable; diff --git a/frontend-graph/src/components/Graph/GraphViewModal.tsx b/frontend-graph/src/components/Graph/GraphViewModal.tsx new file mode 100644 index 000000000..e1c8ae9ba --- /dev/null +++ b/frontend-graph/src/components/Graph/GraphViewModal.tsx @@ -0,0 +1,589 @@ +import { + Banner, + Dialog, + Flex, + IconButtonArray, + LoadingSpinner, + useDebounceValue, +} from "@neo4j-ndl/react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { + BasicNode, + BasicRelationship, + EntityType, + ExtendedNode, + ExtendedRelationship, + GraphType, + GraphViewModalProps, + OptionType, + Scheme, +} from "../../types"; +import { InteractiveNvlWrapper } from "@neo4j-nvl/react"; +import NVL from "@neo4j-nvl/base"; +import type { Node, Relationship } from "@neo4j-nvl/base"; +import { + ArrowPathIconOutline, + FitToScreenIcon, + InformationCircleIconOutline, + MagnifyingGlassMinusIconOutline, + MagnifyingGlassPlusIconOutline, + ExploreIcon, +} from "@neo4j-ndl/react/icons"; +import { IconButtonWithToolTip } from "../UI/IconButtonToolTip"; +import { + filterData, + getCheckboxConditions, + graphTypeFromNodes, + processGraphData, +} from "../../utils/Utils"; +import { getGraphSchema, graphQueryAPI } from "../../services/GraphQuery"; +import { graphLabels, nvlOptions, queryMap } from "../../utils/Constants"; +import CheckboxSelection from "./CheckboxSelection"; +import ResultOverview from "./ResultOverview"; +import { ResizePanelDetails } from "./ResizePanel"; +import GraphPropertiesPanel from "./GraphPropertiesPanel"; +import { extractGraphSchemaFromRawData } from "../../utils/Utils"; + +const GraphViewModal: React.FunctionComponent = ({ + open, + inspectedName, + setGraphViewOpen, + viewPoint, + nodeValues, + relationshipValues, + selectedRows, +}) => { + const nvlRef = useRef(null); + const [node, setNode] = useState([]); + const [relationship, setRelationship] = useState([]); + const [allNodes, setAllNodes] = useState([]); + const [allRelationships, setAllRelationships] = useState([]); + const [loading, setLoading] = useState(false); + const [status, setStatus] = useState<"unknown" | "success" | "danger">( + "unknown" + ); + const [statusMessage, setStatusMessage] = useState(""); + const [scheme, setScheme] = useState({}); + const [newScheme, setNewScheme] = useState({}); + const [searchQuery, setSearchQuery] = useState(""); + const [debouncedQuery] = useDebounceValue(searchQuery, 300); + const [graphType, setGraphType] = useState([]); + const [disableRefresh, setDisableRefresh] = useState(false); + const [selected, setSelected] = useState< + { type: EntityType; id: string } | undefined + >(undefined); + const [mode, setMode] = useState(false); + const graphQueryAbortControllerRef = useRef(); + const [openGraphView, setOpenGraphView] = useState(false); + const [schemaNodes, setSchemaNodes] = useState([]); + const [schemaRels, setSchemaRels] = useState([]); + const [viewCheck, setViewcheck] = useState("enhancement"); + + const graphQuery: string = + graphType.includes("DocumentChunk") && graphType.includes("Entities") + ? queryMap.DocChunkEntities + : graphType.includes("DocumentChunk") + ? queryMap.DocChunks + : graphType.includes("Entities") + ? queryMap.Entities + : ""; + + // fit graph to original position + const handleZoomToFit = () => { + nvlRef.current?.fit( + allNodes.map((node) => node.id), + {} + ); + }; + + // Unmounting the component + useEffect(() => { + const timeoutId = setTimeout(() => { + handleZoomToFit(); + }, 10); + return () => { + if (nvlRef.current) { + nvlRef.current?.destroy(); + } + setGraphType([]); + clearTimeout(timeoutId); + setScheme({}); + setNode([]); + setRelationship([]); + setAllNodes([]); + setAllRelationships([]); + setSearchQuery(""); + setSelected(undefined); + }; + }, []); + + useEffect(() => { + let updateGraphType; + if (mode) { + updateGraphType = graphTypeFromNodes(node); + } else { + updateGraphType = graphTypeFromNodes(allNodes); + } + if (Array.isArray(updateGraphType)) { + setGraphType(updateGraphType); + } + }, [allNodes]); + + const fetchData = useCallback(async () => { + graphQueryAbortControllerRef.current = new AbortController(); + try { + let nodeRelationshipData; + if (viewPoint === graphLabels.showGraphView) { + nodeRelationshipData = await graphQueryAPI( + graphQuery, + selectedRows?.map((f) => f.name), + graphQueryAbortControllerRef.current.signal + ); + } else if (viewPoint === graphLabels.showSchemaView) { + nodeRelationshipData = await getGraphSchema(); + } else { + nodeRelationshipData = await graphQueryAPI( + graphQuery, + [inspectedName ?? ""], + graphQueryAbortControllerRef.current.signal + ); + } + return nodeRelationshipData; + } catch (error: any) { + console.log(error); + } + }, [viewPoint, selectedRows, graphQuery, inspectedName]); + + // Api call to get the nodes and relations + const graphApi = async (mode?: string) => { + try { + const result = await fetchData(); + if (result && result.data.data.nodes.length > 0) { + const neoNodes = result.data.data.nodes; + const nodeIds = new Set(neoNodes.map((node: any) => node.element_id)); + const neoRels = result.data.data.relationships + .map((f: Relationship) => f) + .filter( + (rel: any) => + nodeIds.has(rel.end_node_element_id) && + nodeIds.has(rel.start_node_element_id) + ); + const { finalNodes, finalRels, schemeVal } = processGraphData( + neoNodes, + neoRels + ); + + if (mode === "refreshMode") { + initGraph(graphType, finalNodes, finalRels, schemeVal); + } else { + setNode(finalNodes); + setRelationship(finalRels); + setNewScheme(schemeVal); + setLoading(false); + } + setAllNodes(finalNodes); + setAllRelationships(finalRels); + setScheme(schemeVal); + setDisableRefresh(false); + } else { + setLoading(false); + setStatus("danger"); + setStatusMessage( + `No Nodes and Relations for the ${inspectedName} file` + ); + } + } catch (error: any) { + setLoading(false); + setStatus("danger"); + setStatusMessage(error.message); + } + }; + + useEffect(() => { + if (open) { + // Clear any stuck popups that might be covering the modal + document.querySelectorAll(".popup").forEach((el) => el.remove()); + setLoading(true); + setGraphType([]); + if (viewPoint !== graphLabels.chatInfoView) { + graphApi(); + } else { + const { finalNodes, finalRels, schemeVal } = processGraphData( + nodeValues ?? [], + relationshipValues ?? [] + ); + setAllNodes(finalNodes); + setAllRelationships(finalRels); + setScheme(schemeVal); + setNode(finalNodes); + setRelationship(finalRels); + setNewScheme(schemeVal); + setLoading(false); + } + } + }, [open]); + + useEffect(() => { + if (debouncedQuery) { + handleSearch(debouncedQuery); + } + }, [debouncedQuery]); + + const mouseEventCallbacks = useMemo( + () => ({ + onNodeClick: (clickedNode: Node) => { + if (selected?.id !== clickedNode.id || selected?.type !== "node") { + setSelected({ type: "node", id: clickedNode.id }); + } + }, + onRelationshipClick: (clickedRelationship: Relationship) => { + if ( + selected?.id !== clickedRelationship.id || + selected?.type !== "relationship" + ) { + setSelected({ type: "relationship", id: clickedRelationship.id }); + } + }, + onCanvasClick: () => { + if (selected !== undefined) { + setSelected(undefined); + } + }, + onPan: true, + onZoom: true, + onDrag: true, + }), + [selected] + ); + + const initGraph = ( + graphType: GraphType[], + finalNodes: ExtendedNode[], + finalRels: Relationship[], + schemeVal: Scheme + ) => { + if (allNodes.length > 0 && allRelationships.length > 0) { + const { filteredNodes, filteredRelations, filteredScheme } = filterData( + graphType, + finalNodes ?? [], + finalRels ?? [], + schemeVal + ); + setNode(filteredNodes); + setRelationship(filteredRelations); + setNewScheme(filteredScheme); + } + }; + + const selectedItem = useMemo(() => { + if (selected === undefined) { + return undefined; + } + if (selected.type === "node") { + return node.find((nodeVal) => nodeVal.id === selected.id); + } + return relationship.find( + (relationshipVal) => relationshipVal.id === selected.id + ); + }, [selected, relationship, node]); + + const handleSearch = useCallback( + (value: string) => { + const query = value.toLowerCase(); + const updatedNodes = node.map((nodeVal) => { + if (query === "") { + return { + ...nodeVal, + selected: false, + size: graphLabels.nodeSize, + }; + } + const { id, properties, caption } = nodeVal; + const propertiesMatch = properties?.id?.toLowerCase().includes(query); + const match = + id.toLowerCase().includes(query) || + propertiesMatch || + caption?.toLowerCase().includes(query); + return { + ...nodeVal, + selected: match, + }; + }); + const updatedRelationships = relationship.map((rel) => { + return { + ...rel, + selected: false, + }; + }); + setNode(updatedNodes); + setRelationship(updatedRelationships); + }, + [node, relationship] + ); + + if (!open) { + return <>; + } + + const headerTitle = + viewPoint === graphLabels.showGraphView || + viewPoint === graphLabels.chatInfoView + ? graphLabels.generateGraph + : viewPoint === graphLabels.showSchemaView + ? graphLabels.renderSchemaGraph + : `${graphLabels.inspectGeneratedGraphFrom} ${inspectedName}`; + + const checkBoxView = viewPoint !== graphLabels.chatInfoView; + + const handleCheckboxChange = (graph: GraphType) => { + const currentIndex = graphType.indexOf(graph); + const newGraphSelected = [...graphType]; + if (currentIndex === -1) { + newGraphSelected.push(graph); + } else { + newGraphSelected.splice(currentIndex, 1); + } + initGraph(newGraphSelected, allNodes, allRelationships, scheme); + setSearchQuery(""); + setGraphType(newGraphSelected); + setSelected(undefined); + if (nvlRef.current && nvlRef?.current?.getScale() > 1) { + handleZoomToFit(); + } + }; + + // Callback + const nvlCallbacks = { + onLayoutComputing(isComputing: boolean) { + if (!isComputing) { + handleZoomToFit(); + } + }, + }; + + const handleZoomIn = () => { + nvlRef.current?.setZoom(nvlRef.current.getScale() * 1.3); + }; + + const handleZoomOut = () => { + nvlRef.current?.setZoom(nvlRef.current.getScale() * 0.7); + }; + + // Refresh the graph with nodes and relations if file is processing + const handleRefresh = () => { + setDisableRefresh(true); + setMode(true); + graphApi("refreshMode"); + }; + + // when modal closes reset all states to default + const onClose = () => { + // Clear any stuck popups + document.querySelectorAll(".popup").forEach((el) => el.remove()); + graphQueryAbortControllerRef?.current?.abort(); + setStatus("unknown"); + setStatusMessage(""); + setGraphViewOpen(false); + setScheme({}); + setGraphType([]); + setNode([]); + setRelationship([]); + setAllNodes([]); + setAllRelationships([]); + setSearchQuery(""); + setSelected(undefined); + }; + + const handleSchemaView = async (rawNodes: any[], rawRelationships: any[]) => { + const { nodes, relationships } = extractGraphSchemaFromRawData( + rawNodes, + rawRelationships + ); + setSchemaNodes(nodes as any); + setSchemaRels(relationships as any); + setViewcheck("viz"); + setOpenGraphView(true); + }; + + return ( + <> + + + {headerTitle} + {viewPoint !== graphLabels.chatInfoView && ( +
+ + + + + {graphLabels.chunksInfo} + +
+ )} + + {checkBoxView && ( + + )} + +
+ +
+ {loading ? ( +
+ +
+ ) : status !== "unknown" ? ( +
+ +
+ ) : node.length === 0 && + relationship.length === 0 && + graphType.length !== 0 ? ( +
+ +
+ ) : graphType.length === 0 && checkBoxView ? ( +
+ +
+ ) : ( + <> +
+
+ + + handleSchemaView(node, relationship)} + placement="left" + > + + + + + {viewPoint !== "chatInfoView" && ( + + + + )} + + + + + + + + + + +
+ + {selectedItem !== undefined ? ( + + ) : ( + + )} + +
+ + )} +
+
+
+ + ); +}; +export default GraphViewModal; diff --git a/frontend-graph/src/components/Graph/GraphViewer.tsx b/frontend-graph/src/components/Graph/GraphViewer.tsx new file mode 100644 index 000000000..cda7d72be --- /dev/null +++ b/frontend-graph/src/components/Graph/GraphViewer.tsx @@ -0,0 +1,922 @@ +import React, { useState } from "react"; +import EmbeddedGraphView from "./EmbeddedGraphView"; +import SampleData from "./SampleData"; +import SearchPanel, { SearchParams } from "./SearchPanel"; +import { ExtendedNode, ExtendedRelationship } from "../../types"; +import { + graphQueryAPIWithTransform, + searchAndGetSubgraphAPI, + analyzeRiskAPI, +} from "../../services/GraphQuery"; + +// Tab types +type TabType = "graph" | "search" | "risk"; + +const GraphViewer: React.FC = () => { + const [nodes, setNodes] = useState([]); + const [relationships, setRelationships] = useState( + [] + ); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [showGraph, setShowGraph] = useState(false); + const [newFileName, setNewFileName] = useState(""); + const [searchResult, setSearchResult] = useState(null); + + // Risk assessment state + const [riskAssessment, setRiskAssessment] = useState(null); + const [riskLoading, setRiskLoading] = useState(false); + + // Search loading state + const [searchLoading, setSearchLoading] = useState(false); + + // Tab management state + const [activeTab, setActiveTab] = useState("graph"); + + // Connection form state + const [connectionForm, setConnectionForm] = useState<{ + uri: string; + userName: string; + password: string; + database: string; + documentNames: string[]; + }>({ + uri: "neo4j+ssc://224c5da6.databases.neo4j.io", + userName: "neo4j", + password: "", + database: "neo4j", + documentNames: [], // Disabled default document names + }); + + const handleLoadSampleData = ( + sampleNodes: ExtendedNode[], + sampleRelationships: ExtendedRelationship[] + ) => { + setNodes(sampleNodes); + setRelationships(sampleRelationships); + setError(null); + setShowGraph(false); // Reset graph view when new data is loaded + setSearchResult(null); // Clear search results + }; + + const handleLoadBackendData = async () => { + setLoading(true); + setError(null); + + try { + console.log("Starting backend data load..."); + + // Create an AbortController for the API call + const abortController = new AbortController(); + + // Set a timeout to abort the request if it takes too long + const timeoutId = setTimeout(() => { + console.log("Request timeout - aborting"); + abortController.abort(); + }, 60000); // 60 second timeout + + // Fetch graph data from backend with connection parameters + const response = await graphQueryAPIWithTransform( + "entities", // query_type + connectionForm.documentNames, // document_names + abortController.signal, + connectionForm // connection parameters + ); + + // Clear the timeout since we got a response + clearTimeout(timeoutId); + + // Extract the transformed data + const { nodes: backendNodes, relationships: backendRelationships } = + response.data.data; + + setNodes(backendNodes); + setRelationships(backendRelationships); + setShowGraph(false); // Reset graph view when new data is loaded + setSearchResult(null); // Clear search results + + console.log( + `Loaded ${backendNodes.length} nodes and ${backendRelationships.length} relationships from backend` + ); + } catch (err: any) { + console.error("Error loading backend data:", err); + if (err.name === "AbortError") { + setError( + "Request was cancelled due to timeout. The backend is taking too long to respond." + ); + } else { + setError( + err.message || + "Failed to load data from backend. Check your connection details." + ); + } + } finally { + setLoading(false); + } + }; + + const handleSearch = async (searchParams: SearchParams) => { + setSearchLoading(true); + setError(null); + + try { + console.log("Starting search...", searchParams); + + // Create an AbortController for the API call + const abortController = new AbortController(); + + // Set a timeout to abort the request if it takes too long + const timeoutId = setTimeout(() => { + console.log("Search request timeout - aborting"); + abortController.abort(); + }, 120000); // 2 minute timeout for search operations + + // Perform search and subgraph extraction + const response = await searchAndGetSubgraphAPI( + searchParams.search_term, + searchParams.node_type, + searchParams.depth, + searchParams.max_results, + abortController.signal, + connectionForm + ); + + // Clear the timeout since we got a response + clearTimeout(timeoutId); + + // Extract the search results + const searchData = response.data.data; + setSearchResult(searchData); + + console.log( + `Search completed: ${searchData.total_results} total results, ${searchData.subgraphs.length} subgraphs` + ); + } catch (err: any) { + console.error("Error during search:", err); + if (err.name === "AbortError") { + setError( + "Search was cancelled due to timeout. The backend is taking too long to respond." + ); + } else { + setError( + err.message || + "Failed to perform search. Check your connection details and search parameters." + ); + } + } finally { + setSearchLoading(false); + } + }; + + const handleViewSubgraph = (subgraph: any) => { + // Transform the subgraph data to match the expected format + const transformedNodes: ExtendedNode[] = subgraph.nodes.map( + (node: any) => ({ + id: node.element_id, + labels: node.labels, + properties: node.properties, + caption: + node.properties?.name || + node.properties?.title || + node.properties?.id || + "Unnamed Node", + size: 20, + color: "#4CAF50", + }) + ); + + const transformedRelationships: ExtendedRelationship[] = + subgraph.relationships.map((rel: any) => ({ + id: rel.element_id, + type: rel.type, + from: rel.start_node_id, + to: rel.end_node_id, + properties: rel.properties, + caption: rel.type, + color: "#2196F3", + width: 2, + })); + + setNodes(transformedNodes); + setRelationships(transformedRelationships); + setShowGraph(true); + setActiveTab("graph"); // Switch to graph tab + setError(null); + + console.log( + `Loaded subgraph with ${transformedNodes.length} nodes and ${transformedRelationships.length} relationships` + ); + }; + + const handleClearSearch = () => { + setSearchResult(null); + setError(null); + }; + + const handleAnalyzeRisk = async (entityName: string, entityType: string, depth: number, maxResults: number) => { + setRiskLoading(true); + setError(null); + + try { + console.log("Starting risk analysis...", { entityName, entityType, depth, maxResults }); + + // Create an AbortController for the API call + const abortController = new AbortController(); + + // Set a timeout to abort the request if it takes too long + const timeoutId = setTimeout(() => { + console.log("Risk analysis request timeout - aborting"); + abortController.abort(); + }, 120000); // 2 minute timeout for risk analysis + + // Default risk indicators for Canadian research security + const riskIndicators = { + "Foreign State Influence": 80, + "Dual-Use Technology Exposure": 70, + "Compliance with Canadian Research Security Policies": 60, + "International Collaboration Patterns": 50, + "Funding Sources Transparency": 40, + "Export Control Compliance": 45, + "Intellectual Property Protection": 35, + "Research Data Security": 30, + }; + + // Perform risk analysis with depth and max_results from search panel + const response = await analyzeRiskAPI( + entityName, + entityType, + riskIndicators, + depth, // depth from search panel + maxResults, // max_results from search panel + abortController.signal, + connectionForm + ); + + // Clear the timeout since we got a response + clearTimeout(timeoutId); + + // Extract the risk assessment results + const riskData = response.data.data; + setRiskAssessment(riskData); + setActiveTab("risk"); // Switch to risk assessment tab + + console.log("Risk analysis completed:", riskData); + } catch (err: any) { + console.error("Error during risk analysis:", err); + if (err.name === "AbortError") { + setError( + "Risk analysis was cancelled due to timeout. The backend is taking too long to respond." + ); + } else { + setError( + err.message || + "Failed to perform risk analysis. Check your connection details and entity information." + ); + } + } finally { + setRiskLoading(false); + } + }; + + const handleConnectionChange = (field: string, value: string | string[]) => { + setConnectionForm((prev) => ({ + ...prev, + [field]: value, + })); + }; + + const handleSaveCredentials = () => { + // Save connection credentials to session storage + sessionStorage.setItem("neo4j_uri", connectionForm.uri); + sessionStorage.setItem("neo4j_username", connectionForm.userName); + sessionStorage.setItem("neo4j_password", connectionForm.password); + sessionStorage.setItem("neo4j_database", connectionForm.database); + + // Show success feedback + alert("Credentials saved to session storage successfully!"); + }; + + // Helper function to render clickable links + const renderClickableSource = (source: string) => { + if (source.startsWith("http://") || source.startsWith("https://")) { + return ( + + {source} + + ); + } + return {source}; + }; + + // Load credentials from session storage on component mount + React.useEffect(() => { + const savedUri = sessionStorage.getItem("neo4j_uri"); + const savedUsername = sessionStorage.getItem("neo4j_username"); + const savedPassword = sessionStorage.getItem("neo4j_password"); + const savedDatabase = sessionStorage.getItem("neo4j_database"); + + if (savedUri || savedUsername || savedPassword || savedDatabase) { + setConnectionForm((prev) => ({ + ...prev, + uri: savedUri || prev.uri, + userName: savedUsername || prev.userName, + password: savedPassword || prev.password, + database: savedDatabase || prev.database, + })); + } + }, []); + + const handleShowGraph = () => { + setShowGraph(true); + }; + + const handleAddFile = () => { + if ( + newFileName.trim() && + !connectionForm.documentNames.includes(newFileName.trim()) + ) { + setConnectionForm((prev) => ({ + ...prev, + documentNames: [...prev.documentNames, newFileName.trim()], + })); + setNewFileName(""); + } + }; + + const handleRemoveFile = (index: number) => { + setConnectionForm((prev) => ({ + ...prev, + documentNames: prev.documentNames.filter((_, i) => i !== index), + })); + }; + + const handleKeyPress = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + e.preventDefault(); + handleAddFile(); + } + }; + + const handleClearAllFiles = () => { + setConnectionForm((prev) => ({ + ...prev, + documentNames: [], + })); + }; + + const handleAddSampleFiles = () => { + const sampleFiles = [ + "Apple stock during pandemic.pdf", + "Market analysis report.pdf", + "Financial statements Q4.pdf", + "Investment portfolio.pdf", + ]; + setConnectionForm((prev) => ({ + ...prev, + documentNames: [...new Set([...prev.documentNames, ...sampleFiles])], + })); + }; + + return ( +
+
+

+ Graph Visualization +

+ + {/* Backend Connection Configuration */} +
+
+

+ Backend Connection +

+

+ Configure your Neo4j connection and load real graph data from your + backend. +

+
+ +
+
+ + handleConnectionChange("uri", e.target.value)} + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + placeholder="neo4j://localhost:7687" + /> +
+ +
+ + + handleConnectionChange("database", e.target.value) + } + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + placeholder="neo4j" + /> +
+ +
+ + + handleConnectionChange("userName", e.target.value) + } + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + placeholder="neo4j" + /> +
+ +
+ + + handleConnectionChange("password", e.target.value) + } + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + placeholder="โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข" + /> +
+
+ +
+ +
+
+ + + + {/* Search Panel */} + + + {/* Tabbed Content Area */} +
+ {/* Tab Navigation */} +
+ +
+ + {/* Tab Content */} +
+ {/* Graph Tab */} + {activeTab === "graph" && ( +
+ {showGraph && nodes.length > 0 ? ( + + ) : ( +
+ + + +

No Graph Data

+

+ Load sample data or search for entities to visualize the + graph. +

+
+ +
+
+ )} +
+ )} + + {/* Search Results Tab */} + {activeTab === "search" && ( +
+ {searchLoading ? ( +
+
+ + + + + Extracting Subgraph... +
+
+ ) : searchResult ? ( +
+
+

Search Results

+ +
+
+ {searchResult.subgraphs.map( + (subgraph: any, index: number) => ( +
+
+

+ Subgraph {index + 1} +

+ +
+
+

Nodes: {subgraph.nodes.length}

+

+ Relationships: {subgraph.relationships.length} +

+
+
+ ) + )} +
+
+ ) : ( +
+ + + +

+ No Search Results +

+

+ Use the search panel above to find entities and extract + subgraphs. +

+
+ )} +
+ )} + + {/* Risk Assessment Tab */} + {activeTab === "risk" && ( +
+ {riskLoading ? ( +
+
+ + + + + Analyzing Risk... +
+
+ ) : riskAssessment ? ( +
+
+

+ Risk Assessment Results +

+ +
+ + {/* Entity Information */} +
+

+ Entity Details +

+
+
+ Name: + + {riskAssessment.entityName} + +
+
+ Type: + + {riskAssessment.entityType} + +
+
+
+ + {/* Overall Assessment */} +
+

+ Overall Assessment +

+
+
+ + Score: + + + {riskAssessment.calculation?.overallScore || "N/A"} + +
+
+ + Status: + + + {riskAssessment.finalAssessment?.trafficLight || + "N/A"} + +
+
+

+ {riskAssessment.finalAssessment?.overallExplanation || + "No explanation available."} +

+
+ + {/* Risk Indicators */} +
+

+ Risk Indicators +

+ {riskAssessment.riskAssessments?.map( + (assessment: any, index: number) => ( +
+
+
+ {assessment.indicator} +
+
+ + Score: + + + {assessment.score}/5 + + + Weight: + + + {assessment.weight} + +
+
+

+ {assessment.explanation} +

+ {assessment.sources && + assessment.sources.length > 0 && ( +
+ + Sources: + +
+ {assessment.sources.map( + (source: string, sourceIndex: number) => ( +
+ {renderClickableSource(source)} +
+ ) + )} +
+
+ )} +
+ ) + )} +
+ + {/* Analysis Metadata */} + {riskAssessment.analysis_metadata && ( +
+

+ Analysis Details +

+
+
+ + Chunks Analyzed: + + + {riskAssessment.analysis_metadata.chunks_analyzed} + +
+
+ + Subgraph Nodes: + + + {riskAssessment.analysis_metadata.subgraph_nodes} + +
+
+ + Search Method: + + + {riskAssessment.analysis_metadata.search_method} + +
+
+ + Best Match Score: + + + { + riskAssessment.analysis_metadata + .best_match_score + } + +
+
+
+ )} +
+ ) : ( +
+ + + +

+ No Risk Assessment +

+

+ Use the "Analyze Risk" button in the search panel to + assess entity risk. +

+
+ )} +
+ )} +
+
+ + {/* Error Display */} + {error && ( +
+

Error

+

{error}

+
+ )} +
+
+ ); +}; + +export default GraphViewer; diff --git a/frontend-graph/src/components/Graph/LegendsChip.tsx b/frontend-graph/src/components/Graph/LegendsChip.tsx new file mode 100644 index 000000000..590c253b2 --- /dev/null +++ b/frontend-graph/src/components/Graph/LegendsChip.tsx @@ -0,0 +1,21 @@ +import { LegendChipProps } from "../../types"; +import { graphLabels } from "../../utils/Constants"; +import Legend from "../UI/Legend"; + +export const LegendsChip: React.FunctionComponent = ({ + scheme, + label, + type, + count, + onClick, +}) => { + return ( + + ); +}; diff --git a/frontend-graph/src/components/Graph/ResizePanel.tsx b/frontend-graph/src/components/Graph/ResizePanel.tsx new file mode 100644 index 000000000..13a909d1c --- /dev/null +++ b/frontend-graph/src/components/Graph/ResizePanel.tsx @@ -0,0 +1,60 @@ +import { DragIcon } from "@neo4j-ndl/react/icons"; +import type { ResizeCallback } from "re-resizable"; +import { Resizable } from "re-resizable"; + +type ResizePanelProps = { + children: React.ReactNode; + open: boolean; + onResizeStop?: ResizeCallback; + defaultWidth?: number; +}; + +export const ResizePanelDetails = ({ + children, + open, + onResizeStop, +}: ResizePanelProps) => { + if (!open) { + return null; + } + return ( + , + }} + handleClasses={{ left: "ml-1" }} + onResizeStop={onResizeStop} + > +
{children}
+
+ ); +}; +const Title = ({ children }: { children: React.ReactNode }) => { + return ( +
+ {children} +
+ ); +}; +ResizePanelDetails.Title = Title; + +const Content = ({ children }: { children: React.ReactNode }) => { + return
{children}
; +}; +ResizePanelDetails.Content = Content; diff --git a/frontend-graph/src/components/Graph/ResultOverview.tsx b/frontend-graph/src/components/Graph/ResultOverview.tsx new file mode 100644 index 000000000..c55051cfc --- /dev/null +++ b/frontend-graph/src/components/Graph/ResultOverview.tsx @@ -0,0 +1,211 @@ +import { Flex, IconButton, TextInput, Typography } from "@neo4j-ndl/react"; +import { MagnifyingGlassIconOutline } from "@neo4j-ndl/react/icons"; +import { LegendsChip } from "./LegendsChip"; +import { ExtendedNode, ExtendedRelationship, Scheme } from "../../types"; +import { graphLabels, RESULT_STEP_SIZE } from "../../utils/Constants"; +import type { Relationship } from "@neo4j-nvl/base"; +import { ShowAll } from "../UI/ShowAll"; +import { Dispatch, SetStateAction } from "react"; + +interface OverViewProps { + nodes: ExtendedNode[]; + relationships: ExtendedRelationship[]; + newScheme: Scheme; + searchQuery: string; + setSearchQuery: Dispatch>; + setNodes: Dispatch>; + setRelationships: Dispatch>; +} + +const ResultOverview: React.FunctionComponent = ({ + nodes, + relationships, + newScheme, + searchQuery, + setSearchQuery, + setNodes, + setRelationships, +}) => { + const nodeCount = (nodes: ExtendedNode[], label: string): number => { + return [ + ...new Set( + nodes?.filter((n) => n.labels?.includes(label)).map((i) => i.id) + ), + ].length; + }; + + // sort the legends in with Chunk and Document always the first two values + const nodeCheck = Object.keys(newScheme).sort((a, b) => { + if (a === graphLabels.document || a === graphLabels.chunk) { + return -1; + } else if (b === graphLabels.document || b === graphLabels.chunk) { + return 1; + } + return a.localeCompare(b); + }); + + // get sorted relationships + const relationshipsSorted = relationships.sort((a, b) => + a.type.localeCompare(b.type) + ); + + const relationshipCount = ( + relationships: ExtendedRelationship[], + label: string + ): number => { + return [ + ...new Set( + relationships + ?.filter((r) => r.caption?.includes(label)) + .map((i) => i.id) + ), + ].length; + }; + + // To get the relationship count + const groupedAndSortedRelationships: ExtendedRelationship[] = Object.values( + relationshipsSorted.reduce( + (acc: { [key: string]: ExtendedRelationship }, relType: Relationship) => { + const key = relType.caption || ""; + if (!acc[key]) { + acc[key] = { ...relType, count: 0 }; + } + (acc[key] as { count: number }).count += relationshipCount( + relationships as ExtendedRelationship[], + key + ); + return acc; + }, + {} + ) + ); + + // On Relationship Legend Click, highlight the relationships and deactivating any active nodes + const handleRelationshipClick = (nodeLabel: string) => { + const updatedRelations = relationships.map((rel) => { + return { + ...rel, + selected: rel?.caption?.includes(nodeLabel), + }; + }); + + // // deactivating any active nodes + const updatedNodes = nodes.map((node) => { + return { + ...node, + selected: false, + size: graphLabels.nodeSize, + }; + }); + if (searchQuery !== "") { + setSearchQuery(""); + } + setRelationships(updatedRelations); + setNodes(updatedNodes); + }; + + // On Node Click, highlighting the nodes and deactivating any active relationships + const handleNodeClick = (nodeLabel: string) => { + const updatedNodes = nodes.map((node) => { + const isActive = node.labels.includes(nodeLabel); + return { + ...node, + selected: isActive, + }; + }); + // deactivating any active relationships + const updatedRelationships = relationships.map((rel) => { + return { + ...rel, + selected: false, + }; + }); + if (searchQuery !== "") { + setSearchQuery(""); + } + setNodes(updatedNodes); + setRelationships(updatedRelationships); + }; + + return ( + <> + {nodeCheck.length > 0 && ( + <> + + {graphLabels.resultOverview} +
+ { + setSearchQuery(e.target.value); + }} + isFluid={true} + leftElement={ + + + + } + /> +
+ + {graphLabels.totalNodes} ({nodes.length}) + +
+
+ + {nodeCheck.map((nodeLabel) => ( + handleNodeClick(nodeLabel)} + /> + ))} + +
+ + )} + {relationshipsSorted.length > 0 && ( + <> + + + {graphLabels.totalRelationships} ({relationships.length}) + + +
+ + {groupedAndSortedRelationships.map((relType, index) => ( + handleRelationshipClick(relType.caption || "")} + scheme={{}} + /> + ))} + +
+ + )} + + ); +}; + +export default ResultOverview; diff --git a/frontend-graph/src/components/Graph/RiskAssessmentModal.tsx b/frontend-graph/src/components/Graph/RiskAssessmentModal.tsx new file mode 100644 index 000000000..6eb78418e --- /dev/null +++ b/frontend-graph/src/components/Graph/RiskAssessmentModal.tsx @@ -0,0 +1,292 @@ +import React from "react"; +import { Button, Modal, Typography } from "@neo4j-ndl/react"; +import { XMarkIconOutline } from "@neo4j-ndl/react/icons"; + +interface RiskAssessment { + indicator: string; + weight: number; + score: number; + explanation: string; + sources: string[]; + normalizedWeight: number; + weightedContribution: number; +} + +interface RiskAssessmentResult { + entityName: string; + entityType: string; + riskAssessments: RiskAssessment[]; + calculation: { + totalWeight: number; + overallScore: number; + thresholdsApplied: { + red: string; + yellow: string; + blue: string; + }; + }; + finalAssessment: { + trafficLight: "Red" | "Yellow" | "Blue"; + overallExplanation: string; + }; + analysis_metadata?: { + chunks_analyzed: number; + subgraph_nodes: number; + subgraph_relationships: number; + search_method: string; + best_match_score: number | string; + }; +} + +interface RiskAssessmentModalProps { + isOpen: boolean; + onClose: () => void; + riskAssessment: RiskAssessmentResult | null; + loading: boolean; +} + +const RiskAssessmentModal: React.FC = ({ + isOpen, + onClose, + riskAssessment, + loading, +}) => { + const getTrafficLightColor = (trafficLight: string) => { + switch (trafficLight) { + case "Red": + return "bg-red-500"; + case "Yellow": + return "bg-yellow-500"; + case "Blue": + return "bg-blue-500"; + default: + return "bg-gray-500"; + } + }; + + const getScoreColor = (score: number) => { + if (score >= 4) return "text-red-600"; + if (score >= 2.5) return "text-yellow-600"; + return "text-blue-600"; + }; + + if (!isOpen) return null; + + return ( + +
+
+ Risk Assessment Results + +
+ + {loading && ( +
+
+ + Analyzing risk... + +
+ )} + + {!loading && riskAssessment && ( +
+ {/* Entity Information */} +
+
+
+ + {riskAssessment.entityName} + + + Entity Type: {riskAssessment.entityType} + +
+
+
+ + {riskAssessment.finalAssessment.trafficLight} + +
+
+
+ + {/* Overall Score */} +
+ + Overall Risk Score + +
+
+ + {riskAssessment.calculation.overallScore.toFixed(2)} + + + out of 5.0 + +
+
+ + {riskAssessment.finalAssessment.overallExplanation} + +
+
Red: โ‰ฅ 4.0 (High Risk)
+
Yellow: 2.5 - 3.99 (Medium Risk)
+
Blue: < 2.5 (Low Risk)
+
+
+
+
+ + {/* Individual Risk Assessments */} +
+ Risk Indicators + {riskAssessment.riskAssessments.map((assessment, index) => ( +
+
+
+ + {assessment.indicator} + +
+ Weight: {assessment.weight} + Score: {assessment.score}/5 + + Contribution:{" "} + {assessment.weightedContribution.toFixed(3)} + +
+
+ = 4 + ? "bg-red-100 text-red-800" + : assessment.score >= 2.5 + ? "bg-yellow-100 text-yellow-800" + : "bg-blue-100 text-blue-800" + }`} + > + {assessment.score}/5 + +
+ + + {assessment.explanation} + + +
+ + Sources: + +
+ {assessment.sources.length > 0 ? ( + assessment.sources.map((source, sourceIndex) => ( + + {source === "nil" ? "No source available" : source} + + )) + ) : ( + + No sources available + + )} +
+
+
+ ))} +
+ + {/* Analysis Metadata */} + {riskAssessment.analysis_metadata && ( +
+ + Analysis Information + +
+
+ + Chunks Analyzed + + + {riskAssessment.analysis_metadata.chunks_analyzed} + +
+
+ + Subgraph Nodes + + + {riskAssessment.analysis_metadata.subgraph_nodes} + +
+
+ + Search Method + + + {riskAssessment.analysis_metadata.search_method} + +
+
+ + Match Score + + + {riskAssessment.analysis_metadata.best_match_score} + +
+
+
+ )} +
+ )} + + {!loading && !riskAssessment && ( +
+ + No risk assessment data available + +
+ )} + +
+ +
+
+
+ ); +}; + +export default RiskAssessmentModal; diff --git a/frontend-graph/src/components/Graph/SampleData.tsx b/frontend-graph/src/components/Graph/SampleData.tsx new file mode 100644 index 000000000..9c1a23b12 --- /dev/null +++ b/frontend-graph/src/components/Graph/SampleData.tsx @@ -0,0 +1,127 @@ +import React from "react"; +import { ExtendedNode, ExtendedRelationship } from "../../types"; + +export const getSampleGraphData = () => { + const sampleNodes: ExtendedNode[] = [ + { + id: "1", + labels: ["Person"], + properties: { + name: "Alice", + age: 30, + occupation: "Engineer", + }, + }, + { + id: "2", + labels: ["Person"], + properties: { + name: "Bob", + age: 25, + occupation: "Designer", + }, + }, + { + id: "3", + labels: ["Company"], + properties: { + name: "TechCorp", + industry: "Technology", + founded: 2020, + }, + }, + { + id: "4", + labels: ["Project"], + properties: { + name: "GraphBuilder", + status: "Active", + description: "LLM Graph Builder Project", + }, + }, + ]; + + const sampleRelationships: ExtendedRelationship[] = [ + { + id: "1", + from: "1", + to: "3", + type: "WORKS_FOR", + properties: { + since: 2022, + role: "Senior Engineer", + }, + }, + { + id: "2", + from: "2", + to: "3", + type: "WORKS_FOR", + properties: { + since: 2023, + role: "UI Designer", + }, + }, + { + id: "3", + from: "1", + to: "4", + type: "LEADS", + properties: { + since: 2024, + }, + }, + { + id: "4", + from: "2", + to: "4", + type: "CONTRIBUTES_TO", + properties: { + role: "Design Lead", + }, + }, + { + id: "5", + from: "1", + to: "2", + type: "COLLABORATES_WITH", + properties: { + projects: ["GraphBuilder"], + }, + }, + ]; + + return { nodes: sampleNodes, relationships: sampleRelationships }; +}; + +interface SampleDataProps { + onLoadSampleData: ( + nodes: ExtendedNode[], + relationships: ExtendedRelationship[] + ) => void; +} + +const SampleData: React.FC = ({ onLoadSampleData }) => { + const handleLoadSample = () => { + const { nodes, relationships } = getSampleGraphData(); + onLoadSampleData(nodes, relationships); + }; + + return ( +
+

Sample Data

+

+ Load sample graph data to test the visualization. This creates a simple + graph with people, companies, and projects. +

+ +
+ ); +}; + +export default SampleData; diff --git a/frontend-graph/src/components/Graph/SearchPanel.tsx b/frontend-graph/src/components/Graph/SearchPanel.tsx new file mode 100644 index 000000000..8e94474e8 --- /dev/null +++ b/frontend-graph/src/components/Graph/SearchPanel.tsx @@ -0,0 +1,217 @@ +import React, { useState } from "react"; +import { Button, TextInput } from "@neo4j-ndl/react"; +import { MagnifyingGlassIconOutline } from "@neo4j-ndl/react/icons"; + +interface SearchPanelProps { + onSearch: (searchParams: SearchParams) => void; + onClear: () => void; + onAnalyzeRisk: (entityName: string, entityType: string, depth: number, maxResults: number) => void; + loading: boolean; + connectionForm: { + uri: string; + userName: string; + password: string; + database: string; + }; +} + +export interface SearchParams { + search_term: string; + node_type: string; + depth: number; + max_results: number; +} + +const SearchPanel: React.FC = ({ + onSearch, + onClear, + onAnalyzeRisk, + loading, + connectionForm, +}) => { + const [searchParams, setSearchParams] = useState({ + search_term: "", + node_type: "Person", + depth: 4, + max_results: 10, + }); + + const nodeTypes = [ + { label: "Person", value: "Person" }, + { label: "Organization", value: "Organization" }, + { label: "Location", value: "Location" }, + { label: "Event", value: "Event" }, + { label: "Concept", value: "Concept" }, + { label: "Product", value: "Product" }, + { label: "Technology", value: "Technology" }, + ]; + + const depthOptions = [ + { label: "1 level", value: 1 }, + { label: "2 levels", value: 2 }, + { label: "3 levels", value: 3 }, + { label: "4 levels", value: 4 }, + { label: "5 levels", value: 5 }, + ]; + + const maxResultsOptions = [ + { label: "5 results", value: 5 }, + { label: "10 results", value: 10 }, + { label: "20 results", value: 20 }, + { label: "50 results", value: 50 }, + ]; + + const handleSearch = () => { + if (searchParams.search_term.trim()) { + onSearch(searchParams); + } + }; + + + + const handleAnalyzeRisk = () => { + if (searchParams.search_term.trim()) { + onAnalyzeRisk(searchParams.search_term, searchParams.node_type, searchParams.depth, searchParams.max_results); + } + }; + + const isSearchDisabled = !searchParams.search_term.trim() || loading; + + return ( +
+

Graph Search

+

+ Search for nodes across all documents and extract their subgraphs. +

+ +
+ {/* Search Term Input */} +
+ + + setSearchParams({ ...searchParams, search_term: e.target.value }) + } + placeholder="Enter search term (e.g., person name, organization)" + className="w-full" + isDisabled={loading} + /> +
+ + {/* Node Type Selection */} +
+ + +
+ + {/* Depth Selection */} +
+ + +
+ + {/* Max Results Selection */} +
+ + +
+ + {/* Action Buttons */} +
+ + + +
+
+ + {/* Connection Status */} +
+

+ Connection Status +

+
+
URI: {connectionForm.uri || "Not configured"}
+
Database: {connectionForm.database || "Not configured"}
+
Username: {connectionForm.userName || "Not configured"}
+
+
+
+ ); +}; + +export default SearchPanel; diff --git a/frontend-graph/src/components/Graph/SearchResults.tsx b/frontend-graph/src/components/Graph/SearchResults.tsx new file mode 100644 index 000000000..543c2a5f1 --- /dev/null +++ b/frontend-graph/src/components/Graph/SearchResults.tsx @@ -0,0 +1,167 @@ +import React from "react"; +import { Button } from "@neo4j-ndl/react"; +import { + EyeIconOutline, + InformationCircleIconOutline, +} from "@neo4j-ndl/react/icons"; + +interface SearchResult { + search_term: string; + node_type: string; + total_results: number; + subgraphs: SubgraphResult[]; +} + +interface SubgraphResult { + start_node_id: string; + depth: number; + nodes: any[]; + relationships: any[]; + matching_node: { + element_id: string; + labels: string[]; + properties: Record; + }; +} + +interface SearchResultsProps { + searchResult: SearchResult | null; + onViewSubgraph: (subgraph: SubgraphResult) => void; + onClear: () => void; +} + +const SearchResults: React.FC = ({ + searchResult, + onViewSubgraph, + onClear, +}) => { + if (!searchResult) { + return null; + } + + const getNodeName = (node: any) => { + return ( + node.properties?.name || + node.properties?.title || + node.properties?.id || + node.properties?.description || + "Unnamed Node" + ); + }; + + const getNodeType = (node: any) => { + const labels = node.labels || []; + return labels.find((label: string) => label !== "__Entity__") || "Entity"; + }; + + return ( +
+
+

Search Results

+ +
+ + {/* Search Summary */} +
+
+ + + Search Summary + +
+
+

+ Search Term: "{searchResult.search_term}" +

+

+ Node Type: {searchResult.node_type} +

+

+ Total Results: {searchResult.total_results} +

+

+ Subgraphs Found: {searchResult.subgraphs.length} +

+
+
+ + {/* Results */} + {searchResult.subgraphs.length === 0 ? ( +
+

No subgraphs found for the search criteria.

+

+ Try adjusting your search term or node type. +

+
+ ) : ( +
+ {searchResult.subgraphs.map((subgraph, index) => ( +
+
+
+

+ {getNodeName(subgraph.matching_node)} +

+
+ + {getNodeType(subgraph.matching_node)} + + + Depth: {subgraph.depth} + +
+
+

+ Nodes: {subgraph.nodes.length} +

+

+ Relationships:{" "} + {subgraph.relationships.length} +

+
+
+ +
+ + {/* Node Properties Preview */} + {subgraph.matching_node.properties && ( +
+

Properties:

+
+ {Object.entries(subgraph.matching_node.properties) + .slice(0, 6) + .map(([key, value]) => ( +
+ + {key}: + + + {String(value).slice(0, 30)} + {String(value).length > 30 ? "..." : ""} + +
+ ))} +
+
+ )} +
+ ))} +
+ )} +
+ ); +}; + +export default SearchResults; diff --git a/frontend-graph/src/components/UI/IconButtonToolTip.tsx b/frontend-graph/src/components/UI/IconButtonToolTip.tsx new file mode 100644 index 000000000..654d15723 --- /dev/null +++ b/frontend-graph/src/components/UI/IconButtonToolTip.tsx @@ -0,0 +1,80 @@ +import { IconButton, Tooltip } from "@neo4j-ndl/react"; +import { useState } from "react"; + +export const IconButtonWithToolTip = ({ + text, + children, + onClick, + size = "medium", + clean, + grouped, + placement = "bottom", + disabled = false, + label, + loading = false, + className = "", +}: { + label: string; + text: string | React.ReactNode; + children: React.ReactNode; + onClick?: React.MouseEventHandler | undefined; + size?: "small" | "medium" | "large"; + clean?: boolean; + grouped?: boolean; + placement?: "bottom" | "top" | "right" | "left"; + disabled?: boolean; + loading?: boolean; + className?: string; +}) => { + const [isHovered, setIsHovered] = useState(false); + return ( + + + setIsHovered(true), + onMouseLeave: () => setIsHovered(false), + }} + isLoading={loading} + > + {children} + + + {isHovered && ( + + {text} + + )} + + ); +}; + +export const IconWithToolTip = ({ + text, + children, + placement = "bottom", +}: { + label: string; + text: string | React.ReactNode; + children: React.ReactNode; + onClick?: React.MouseEventHandler | undefined; + size?: "small" | "medium" | "large"; + clean?: boolean; + grouped?: boolean; + placement?: "bottom" | "top" | "right" | "left"; + disabled?: boolean; +}) => { + return ( + + {children} + {text} + + ); +}; diff --git a/frontend-graph/src/components/UI/Legend.tsx b/frontend-graph/src/components/UI/Legend.tsx new file mode 100644 index 000000000..46d0fd3d6 --- /dev/null +++ b/frontend-graph/src/components/UI/Legend.tsx @@ -0,0 +1,27 @@ +import { GraphLabel } from "@neo4j-ndl/react"; + +export default function Legend({ + bgColor, + title, + count, + type, + onClick, +}: { + bgColor: string; + title: string; + count?: number; + type: "node" | "relationship" | "propertyKey"; + tabIndex?: number; + onClick?: (e: React.MouseEvent) => void; +}) { + return ( + + {title} {count !== undefined && `(${count})`} + + ); +} diff --git a/frontend-graph/src/components/UI/ShowAll.tsx b/frontend-graph/src/components/UI/ShowAll.tsx new file mode 100644 index 000000000..df864d3f8 --- /dev/null +++ b/frontend-graph/src/components/UI/ShowAll.tsx @@ -0,0 +1,39 @@ +import { Button } from "@neo4j-ndl/react"; +import type { ReactNode } from "react"; +import { useState } from "react"; + +type ShowAllProps = { + initiallyShown: number; + children: ((() => ReactNode) | ReactNode)[]; + ariaLabel?: string; +}; +const isThunkComponent = ( + t: (() => ReactNode) | ReactNode +): t is () => ReactNode => typeof t === "function"; + +export function ShowAll({ initiallyShown, children }: ShowAllProps) { + const [expanded, setExpanded] = useState(false); + const toggleExpanded = () => setExpanded((e) => !e); + const itemCount = children.length; + const controlsNeeded = itemCount > initiallyShown; + const shown = expanded ? itemCount : initiallyShown; + const leftToShow = itemCount - shown; + + if (itemCount === 0) { + return null; + } + + const currentChildren = children + .slice(0, shown) + .map((c) => (isThunkComponent(c) ? c() : c)); + return ( + <> +
{currentChildren}
+ {controlsNeeded && ( + + )} + + ); +} diff --git a/frontend-graph/src/index.css b/frontend-graph/src/index.css new file mode 100644 index 000000000..b6f06a2fe --- /dev/null +++ b/frontend-graph/src/index.css @@ -0,0 +1,21 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentColor); + } +} + +body { + margin: 0; +} + +.ndl-progress-bar-wrapper .ndl-header .ndl-heading::after { + animation: none !important; +} diff --git a/frontend-graph/src/main.tsx b/frontend-graph/src/main.tsx new file mode 100644 index 000000000..3453244bd --- /dev/null +++ b/frontend-graph/src/main.tsx @@ -0,0 +1,11 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./index.css"; +import "@neo4j-ndl/base/lib/neo4j-ds-styles.css"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + +); diff --git a/frontend-graph/src/services/GraphQuery.ts b/frontend-graph/src/services/GraphQuery.ts new file mode 100644 index 000000000..fb1acb20a --- /dev/null +++ b/frontend-graph/src/services/GraphQuery.ts @@ -0,0 +1,437 @@ +import axios from "axios"; + +//TO-DO from env +const API_BASE_URL = "http://localhost:8000"; + +const api = axios.create({ + baseURL: API_BASE_URL, + timeout: 150000, +}); + +interface ConnectionParams { + uri: string; + userName: string; + password: string; + database: string; +} + +export const graphQueryAPI = async ( + query_type: string, + document_names: (string | undefined)[] | undefined, + signal: AbortSignal, + connectionParams?: ConnectionParams +) => { + try { + console.log("Making API call with params:", { + query_type, + document_names, + connectionParams: connectionParams + ? { + uri: connectionParams.uri, + userName: connectionParams.userName, + database: connectionParams.database, + password: "***", //hide pass + } + : "none", + }); + + const formData = new FormData(); + formData.append("query_type", query_type ?? "entities"); + formData.append("document_names", JSON.stringify(document_names)); + + if (connectionParams) { + formData.append("uri", connectionParams.uri); + formData.append("userName", connectionParams.userName); + formData.append("password", connectionParams.password); + formData.append("database", connectionParams.database); + } + + // console.log("Sending request to:", `${API_BASE_URL}/graph_query`); + // console.log("FormData contents:"); + // for (const [key, value] of formData.entries()) { + // console.log(`${key}:`, key === "password" ? "***" : value); + // } + + const response = await api.post(`/graph_query`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + signal, + }); + return response; + } catch (error: any) { + console.error("Error getting the Nodes or Relationships:", error); + if (error.code === "ECONNABORTED") { + throw new Error( + "Request timed out. The backend is taking too long to respond. Please check if your backend is running and try again." + ); + } else if (error.response) { + throw new Error( + `Backend error: ${error.response.status} - ${error.response.data?.detail || error.response.statusText}` + ); + } else if (error.request) { + throw new Error( + "No response from backend. Please check if your backend is running" + ); + } else { + throw new Error(`Request failed: ${error.message}`); + } + } +}; + +export const getNeighbors = async (elementId: string) => { + try { + const formData = new FormData(); + formData.append("elementId", elementId); + + const response = await api.post(`/get_neighbours`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }); + return response; + } catch (error) { + console.log("Error getting the Neighbors:", error); + throw error; + } +}; + +export const getGraphSchema = async () => { + try { + const formData = new FormData(); + const response = await api.post(`/schema_visualization`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }); + return response; + } catch (error) { + console.log("Error getting the Schema:", error); + throw error; + } +}; + +// Data transformation functions to convert backend format to frontend format +export const transformBackendData = (backendData: any) => { + console.log("Backend response structure:", backendData); + + // Handle different possible response structures + let nodes, relationships; + + if (backendData.data && backendData.data.data) { + // Expected structure: { data: { data: { nodes: [], relationships: [] } } } + nodes = backendData.data.data.nodes || []; + relationships = backendData.data.data.relationships || []; + } else if (backendData.data) { + // Alternative structure: { data: { nodes: [], relationships: [] } } + nodes = backendData.data.nodes || []; + relationships = backendData.data.relationships || []; + } else { + // Direct structure: { nodes: [], relationships: [] } + nodes = backendData.nodes || []; + relationships = backendData.relationships || []; + } + + // Transform nodes + const transformedNodes = nodes.map((node: any) => ({ + id: node.element_id, + labels: node.labels || [], + properties: node.properties || {}, + })); + + // Transform relationships + const transformedRelationships = relationships.map((rel: any) => ({ + id: rel.element_id, + from: rel.start_node_element_id, + to: rel.end_node_element_id, + type: rel.type, + properties: rel.properties || {}, + })); + + return { + nodes: transformedNodes, + relationships: transformedRelationships, + }; +}; + +// Enhanced graph query with data transformation +export const graphQueryAPIWithTransform = async ( + query_type: string, + document_names: (string | undefined)[] | undefined, + signal: AbortSignal, + connectionParams?: ConnectionParams +) => { + try { + const response = await graphQueryAPI( + query_type, + document_names, + signal, + connectionParams + ); + //console.log("Raw API response:", response); + const transformedData = transformBackendData(response); + return { + ...response, + data: { + ...response.data, + data: transformedData, + }, + }; + } catch (error) { + console.log("Error in graphQueryAPIWithTransform:", error); + throw error; + } +}; + +export const searchNodesAPI = async ( + search_term: string, + node_type: string = "Person", + max_results: number = 50, + signal: AbortSignal, + connectionParams?: ConnectionParams +) => { + try { + console.log("Making search API call with params:", { + search_term, + node_type, + max_results, + connectionParams: connectionParams + ? { + uri: connectionParams.uri, + userName: connectionParams.userName, + database: connectionParams.database, + password: "***", //hide pass + } + : "none", + }); + + const formData = new FormData(); + formData.append("search_term", search_term); + formData.append("node_type", node_type); + formData.append("max_results", max_results.toString()); + + if (connectionParams) { + formData.append("uri", connectionParams.uri); + formData.append("userName", connectionParams.userName); + formData.append("password", connectionParams.password); + formData.append("database", connectionParams.database); + } + + const response = await api.post(`/search_nodes`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + signal, + }); + return response; + } catch (error: any) { + console.error("Error searching nodes:", error); + if (error.code === "ECONNABORTED") { + throw new Error( + "Request timed out. The backend is taking too long to respond. Please check if your backend is running and try again." + ); + } else if (error.response) { + throw new Error( + `Backend error: ${error.response.status} - ${error.response.data?.detail || error.response.statusText}` + ); + } else if (error.request) { + throw new Error( + "No response from backend. Please check if your backend is running" + ); + } else { + throw new Error(`Request failed: ${error.message}`); + } + } +}; + +export const getSubgraphAPI = async ( + node_id: string, + depth: number = 4, + max_nodes: number = 1000, + signal: AbortSignal, + connectionParams?: ConnectionParams +) => { + try { + console.log("Making subgraph API call with params:", { + node_id, + depth, + max_nodes, + connectionParams: connectionParams + ? { + uri: connectionParams.uri, + userName: connectionParams.userName, + database: connectionParams.database, + password: "***", //hide pass + } + : "none", + }); + + const formData = new FormData(); + formData.append("node_id", node_id); + formData.append("depth", depth.toString()); + formData.append("max_nodes", max_nodes.toString()); + + if (connectionParams) { + formData.append("uri", connectionParams.uri); + formData.append("userName", connectionParams.userName); + formData.append("password", connectionParams.password); + formData.append("database", connectionParams.database); + } + + const response = await api.post(`/get_subgraph`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + signal, + }); + return response; + } catch (error: any) { + console.error("Error getting subgraph:", error); + if (error.code === "ECONNABORTED") { + throw new Error( + "Request timed out. The backend is taking too long to respond. Please check if your backend is running and try again." + ); + } else if (error.response) { + throw new Error( + `Backend error: ${error.response.status} - ${error.response.data?.detail || error.response.statusText}` + ); + } else if (error.request) { + throw new Error( + "No response from backend. Please check if your backend is running" + ); + } else { + throw new Error(`Request failed: ${error.message}`); + } + } +}; + +export const searchAndGetSubgraphAPI = async ( + search_term: string, + node_type: string = "Person", + depth: number = 4, + max_results: number = 10, + signal: AbortSignal, + connectionParams?: ConnectionParams +) => { + try { + console.log("Making search and subgraph API call with params:", { + search_term, + node_type, + depth, + max_results, + connectionParams: connectionParams + ? { + uri: connectionParams.uri, + userName: connectionParams.userName, + database: connectionParams.database, + password: "***", //hide pass + } + : "none", + }); + + const formData = new FormData(); + formData.append("search_term", search_term); + formData.append("node_type", node_type); + formData.append("depth", depth.toString()); + formData.append("max_results", max_results.toString()); + + if (connectionParams) { + formData.append("uri", connectionParams.uri); + formData.append("userName", connectionParams.userName); + formData.append("password", connectionParams.password); + formData.append("database", connectionParams.database); + } + + const response = await api.post(`/search_and_get_subgraph`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + signal, + }); + return response; + } catch (error: any) { + console.error("Error searching and getting subgraph:", error); + if (error.code === "ECONNABORTED") { + throw new Error( + "Request timed out. The backend is taking too long to respond. Please check if your backend is running and try again." + ); + } else if (error.response) { + throw new Error( + `Backend error: ${error.response.status} - ${error.response.data?.detail || error.response.statusText}` + ); + } else if (error.request) { + throw new Error( + "No response from backend. Please check if your backend is running" + ); + } else { + throw new Error(`Request failed: ${error.message}`); + } + } +}; + +export const analyzeRiskAPI = async ( + entity_name: string, + entity_type: string, + risk_indicators: Record, + depth: number = 4, + max_results: number = 10, + signal: AbortSignal, + connectionParams?: ConnectionParams +) => { + try { + console.log("Making risk analysis API call with params:", { + entity_name, + entity_type, + risk_indicators, + depth, + max_results, + connectionParams: connectionParams + ? { + uri: connectionParams.uri, + userName: connectionParams.userName, + database: connectionParams.database, + password: "***", //hide pass + } + : "none", + }); + + const formData = new FormData(); + formData.append("entity_name", entity_name); + formData.append("entity_type", entity_type); + formData.append("risk_indicators", JSON.stringify(risk_indicators)); + formData.append("depth", depth.toString()); + formData.append("max_results", max_results.toString()); + + if (connectionParams) { + formData.append("uri", connectionParams.uri); + formData.append("userName", connectionParams.userName); + formData.append("password", connectionParams.password); + formData.append("database", connectionParams.database); + } + + const response = await api.post(`/analyze_risk`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + signal, + }); + return response; + } catch (error: any) { + console.error("Error analyzing risk:", error); + if (error.code === "ECONNABORTED") { + throw new Error( + "Request timed out. The backend is taking too long to respond. Please check if your backend is running and try again." + ); + } else if (error.response) { + throw new Error( + `Backend error: ${error.response.status} - ${error.response.data?.detail || error.response.statusText}` + ); + } else if (error.request) { + throw new Error( + "No response from backend. Please check if your backend is running" + ); + } else { + throw new Error(`Request failed: ${error.message}`); + } + } +}; diff --git a/frontend-graph/src/types.ts b/frontend-graph/src/types.ts new file mode 100644 index 000000000..cf4096d5a --- /dev/null +++ b/frontend-graph/src/types.ts @@ -0,0 +1,126 @@ +import React from "react"; +import type { Node, Relationship } from "@neo4j-nvl/base"; + +export interface OptionType { + readonly value: string; + readonly label: string; +} + +export type GraphType = "Entities" | "DocumentChunk" | "Communities"; + +export type EntityType = "node" | "relationship"; + +export type Scheme = Record; + +export interface ExtendedNode extends Node { + labels: string[]; + properties: { + fileName?: string; + [key: string]: any; + }; +} + +export interface ExtendedRelationship extends Relationship { + count?: number; + startNodeId?: string; + endNodeId?: string; + properties?: Record; +} + +export interface BasicNode { + id: string; + type: string; + labels: string[]; + properties: Record; + propertyTypes: Record; +} + +export interface BasicRelationship { + id: string; + to: string; + from: string; + type: string; + caption: string; +} + +export interface GraphViewModalProps { + open: boolean; + inspectedName?: string; + setGraphViewOpen: React.Dispatch>; + viewPoint: string; + nodeValues?: ExtendedNode[]; + relationshipValues?: ExtendedRelationship[]; + selectedRows?: any[] | undefined; +} + +export interface SchemaViewModalProps { + open: boolean; + inspectedName?: string; + setGraphViewOpen: React.Dispatch>; + viewPoint: string; + nodeValues?: ExtendedNode[] | OptionType[]; + relationshipValues?: ExtendedRelationship[] | string[] | OptionType[]; + selectedRows?: any[] | undefined; + schemaLoading?: boolean; + view?: string; +} + +export interface CheckboxSectionProps { + graphType: GraphType[]; + loading: boolean; + handleChange: (graph: GraphType) => void; + isCommunity: boolean; + isDocChunk: boolean; + isEntity: boolean; +} + +export interface LegendChipProps { + scheme: Scheme; + label: string; + type: "node" | "relationship" | "propertyKey"; + count?: number; + onClick?: (e: React.MouseEvent) => void; +} + +export interface GraphPropertiesPanelProps { + inspectedItem: BasicNode | BasicRelationship; + newScheme: Scheme; +} + +export interface GraphPropertiesTableProps { + propertiesWithTypes: { + key: string; + value: string | number | boolean | []; + }[]; +} + +export interface OverViewProps { + nodes: ExtendedNode[]; + relationships: ExtendedRelationship[]; + newScheme: Scheme; + searchQuery: string; + setSearchQuery: React.Dispatch>; + setNodes: React.Dispatch>; + setRelationships: React.Dispatch< + React.SetStateAction + >; +} + +export interface ResizePanelDetailsProps { + open: boolean; + children: React.ReactNode; +} + +export interface IconButtonWithToolTipProps { + label: string; + text: string; + onClick: () => void; + placement?: "top" | "bottom" | "left" | "right"; + disabled?: boolean; + children: React.ReactNode; +} + +export interface ShowAllProps { + initiallyShown: number; + children: React.ReactNode; +} diff --git a/frontend-graph/src/utils/Constants.ts b/frontend-graph/src/utils/Constants.ts new file mode 100644 index 000000000..cc477b378 --- /dev/null +++ b/frontend-graph/src/utils/Constants.ts @@ -0,0 +1,90 @@ +import { NvlOptions } from "@neo4j-nvl/base"; +import { GraphType, OptionType } from "../types"; + +export const GRAPH_COLORS = { + node: "#4CAF50", + relationship: "#2196F3", + default: "#9E9E9E", +}; + +export const GRAPH_TYPES = { + ENTITIES: "Entities", + DOCUMENT_CHUNK: "DocumentChunk", + COMMUNITIES: "Communities", +} as const; + +export const DEFAULT_GRAPH_OPTIONS = { + nodeColor: GRAPH_COLORS.node, + relationshipColor: GRAPH_COLORS.relationship, + backgroundColor: "#ffffff", + nodeSize: 20, + relationshipWidth: 2, +}; + +export const nvlOptions: NvlOptions = { + allowDynamicMinZoom: true, + disableWebGL: true, + maxZoom: 3, + minZoom: 0.05, + relationshipThreshold: 0.55, + useWebGL: false, + instanceId: "graph-preview", + initialZoom: 1, +}; + +export const queryMap: { + Document: string; + Chunks: string; + Entities: string; + DocEntities: string; + DocChunks: string; + ChunksEntities: string; + DocChunkEntities: string; +} = { + Document: "document", + Chunks: "chunks", + Entities: "entities", + DocEntities: "docEntities", + DocChunks: "docChunks", + ChunksEntities: "chunksEntities", + DocChunkEntities: "docChunkEntities", +}; + +export const graphView: OptionType[] = [ + { label: "Lexical Graph", value: queryMap.DocChunks }, + { label: "Entity Graph", value: queryMap.Entities }, + { label: "Knowledge Graph", value: queryMap.DocChunkEntities }, +]; + +export const intitalGraphType = (isGDSActive: boolean): GraphType[] => { + return isGDSActive + ? ["DocumentChunk", "Entities", "Communities"] // GDS is active, include communities + : ["DocumentChunk", "Entities"]; // GDS is inactive, exclude communities +}; + +export const graphLabels = { + showGraphView: "showGraphView", + chatInfoView: "chatInfoView", + generateGraph: "Generated Graph", + inspectGeneratedGraphFrom: "Inspect Generated Graph from", + document: "Document", + chunk: "Chunk", + documentChunk: "DocumentChunk", + entities: "Entities", + resultOverview: "Result Overview", + totalNodes: "Total Nodes", + noEntities: "No Entities Found", + selectCheckbox: "Select atleast one checkbox for graph view", + totalRelationships: "Total Relationships", + nodeSize: 30, + docChunk: "Document & Chunk", + community: "Communities", + noNodesRels: "No Nodes and No relationships", + neighborView: "neighborView", + chunksInfo: "We are visualizing 50 chunks at a time", + showSchemaView: "showSchemaView", + renderSchemaGraph: "Graph from Database Schema", + generatedGraphFromUserSchema: "Generated Graph from User Defined Schema", +}; + +export const RESULT_STEP_SIZE = 25; diff --git a/frontend-graph/src/utils/Utils.ts b/frontend-graph/src/utils/Utils.ts new file mode 100644 index 000000000..d476eb6a7 --- /dev/null +++ b/frontend-graph/src/utils/Utils.ts @@ -0,0 +1,218 @@ +import { calcWordColor } from "@neo4j-devtools/word-color"; +import type { Relationship } from "@neo4j-nvl/base"; +import { + ExtendedNode, + ExtendedRelationship, + GraphType, + Scheme, + OptionType, +} from "../types"; + +// Graph Functions +export const getSize = (node: any) => { + const size = node.properties?.size || node.properties?.weight || 1; + return Math.max(10, Math.min(50, size * 20)); +}; + +export const getNodeCaption = (node: any) => { + const caption = + node.properties?.name || + node.properties?.title || + node.properties?.id || + node.id; + return caption?.length > 20 ? caption.substring(0, 20) + "..." : caption; +}; + +export const getIcon = (node: any) => { + // Return undefined to prevent broken image errors since we don't have the SVG assets + return undefined; +}; + +export const processGraphData = ( + neoNodes: ExtendedNode[], + neoRels: ExtendedRelationship[] +) => { + const finalNodes: ExtendedNode[] = neoNodes.map((node) => { + const labels = node.labels || []; + const color = calcWordColor(labels[0] || "default"); + + return { + ...node, + id: node.id, + labels: labels, + properties: node.properties || {}, + caption: getNodeCaption(node), + size: getSize(node), + color: color, + icon: getIcon(node), + }; + }); + + const finalRels: ExtendedRelationship[] = neoRels.map((rel) => { + const color = calcWordColor(rel.type || "default"); + + return { + ...rel, + id: rel.id, + type: rel.type, + from: rel.startNodeId || rel.from, + to: rel.endNodeId || rel.to, + caption: rel.type, + color: color, + width: 2, + }; + }); + + const scheme: Scheme = {}; + finalNodes.forEach((node) => { + node.labels.forEach((label) => { + if (!scheme[label]) { + scheme[label] = calcWordColor(label); + } + }); + }); + + finalRels.forEach((rel) => { + if (!scheme[rel.type]) { + scheme[rel.type] = calcWordColor(rel.type); + } + }); + + return { finalNodes, finalRels, schemeVal: scheme }; +}; + +export const filterData = ( + graphType: GraphType[], + allNodes: ExtendedNode[], + allRelationships: Relationship[], + scheme: Scheme +) => { + const filteredNodes: ExtendedNode[] = []; + const filteredRelations: ExtendedRelationship[] = []; + const filteredScheme: Scheme = {}; + + if (graphType.includes("Entities")) { + const entityNodes = allNodes.filter((node) => + node.labels.some( + (label) => !label.includes("Chunk") && !label.includes("Community") + ) + ); + filteredNodes.push(...entityNodes); + } + + if (graphType.includes("DocumentChunk")) { + const chunkNodes = allNodes.filter((node) => + node.labels.some((label) => label.includes("Chunk")) + ); + filteredNodes.push(...chunkNodes); + } + + if (graphType.includes("Communities")) { + const communityNodes = allNodes.filter((node) => + node.labels.some((label) => label.includes("Community")) + ); + filteredNodes.push(...communityNodes); + } + + // Get relationships between filtered nodes + const nodeIds = new Set(filteredNodes.map((node) => node.id)); + const filteredRels = allRelationships.filter( + (rel) => nodeIds.has(rel.from) && nodeIds.has(rel.to) + ); + + filteredRelations.push(...filteredRels); + + // Build filtered scheme + filteredNodes.forEach((node) => { + node.labels.forEach((label) => { + if (scheme[label] && !filteredScheme[label]) { + filteredScheme[label] = scheme[label]; + } + }); + }); + + filteredRelations.forEach((rel) => { + if (scheme[rel.type] && !filteredScheme[rel.type]) { + filteredScheme[rel.type] = scheme[rel.type]; + } + }); + + return { filteredNodes, filteredRelations, filteredScheme }; +}; + +export const getCheckboxConditions = (allNodes: ExtendedNode[]) => { + const hasEntities = allNodes.some((node) => + node.labels.some( + (label) => !label.includes("Chunk") && !label.includes("Community") + ) + ); + const hasDocChunk = allNodes.some((node) => + node.labels.some((label) => label.includes("Chunk")) + ); + const hasCommunity = allNodes.some((node) => + node.labels.some((label) => label.includes("Community")) + ); + + return { + isEntity: hasEntities, + isDocChunk: hasDocChunk, + isCommunity: hasCommunity, + }; +}; + +export const graphTypeFromNodes = (allNodes: ExtendedNode[]): GraphType[] => { + const graphTypes: GraphType[] = []; + + const hasEntities = allNodes.some((node) => + node.labels.some( + (label) => !label.includes("Chunk") && !label.includes("Community") + ) + ); + const hasDocChunk = allNodes.some((node) => + node.labels.some((label) => label.includes("Chunk")) + ); + const hasCommunity = allNodes.some((node) => + node.labels.some((label) => label.includes("Community")) + ); + + if (hasEntities) graphTypes.push("Entities"); + if (hasDocChunk) graphTypes.push("DocumentChunk"); + if (hasCommunity) graphTypes.push("Communities"); + + return graphTypes; +}; + +export const extractGraphSchemaFromRawData = ( + nodes: any[], + relationships: any[] +): { + nodes: OptionType[]; + relationships: OptionType[]; +} => { + const nodeLabels = new Set(); + const relTypes = new Set(); + + nodes.forEach((node) => { + if (node.labels) { + node.labels.forEach((label: string) => nodeLabels.add(label)); + } + }); + + relationships.forEach((rel) => { + if (rel.type) { + relTypes.add(rel.type); + } + }); + + const nodeOptions: OptionType[] = Array.from(nodeLabels).map((label) => ({ + value: label, + label: label, + })); + + const relOptions: OptionType[] = Array.from(relTypes).map((type) => ({ + value: type, + label: type, + })); + + return { nodes: nodeOptions, relationships: relOptions }; +}; diff --git a/frontend-graph/tailwind.config.js b/frontend-graph/tailwind.config.js new file mode 100644 index 000000000..da7c9efa5 --- /dev/null +++ b/frontend-graph/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git a/frontend-graph/tsconfig.json b/frontend-graph/tsconfig.json new file mode 100644 index 000000000..ce6a6d404 --- /dev/null +++ b/frontend-graph/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} \ No newline at end of file diff --git a/frontend-graph/tsconfig.node.json b/frontend-graph/tsconfig.node.json new file mode 100644 index 000000000..862dfb2b3 --- /dev/null +++ b/frontend-graph/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} \ No newline at end of file diff --git a/frontend-graph/vite.config.ts b/frontend-graph/vite.config.ts new file mode 100644 index 000000000..ab8b9b740 --- /dev/null +++ b/frontend-graph/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + server: { + port: 3000, + host: true + }, + build: { + outDir: 'dist', + sourcemap: true + } +}) \ No newline at end of file diff --git a/frontend-graph/yarn.lock b/frontend-graph/yarn.lock new file mode 100644 index 000000000..5b315c360 --- /dev/null +++ b/frontend-graph/yarn.lock @@ -0,0 +1,5983 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790" + integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw== + +"@babel/core@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4" + integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.27.3" + "@babel/helpers" "^7.27.6" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.0" + "@babel/types" "^7.28.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2" + integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg== + dependencies: + "@babel/parser" "^7.28.0" + "@babel/types" "^7.28.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02" + integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.3" + +"@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.27.6": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.2.tgz#80f0918fecbfebea9af856c419763230040ee850" + integrity sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.2" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.27.2", "@babel/parser@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== + dependencies: + "@babel/types" "^7.28.0" + +"@babel/plugin-transform-react-jsx-self@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz#af678d8506acf52c577cac73ff7fe6615c85fc92" + integrity sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-jsx-source@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz#dcfe2c24094bb757bf73960374e7c55e434f19f0" + integrity sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.28.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473" + integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA== + +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b" + integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.0" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.28.0", "@babel/types@^7.28.2": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b" + integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + +"@dnd-kit/accessibility@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz#3b4202bd6bb370a0730f6734867785919beac6af" + integrity sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw== + dependencies: + tslib "^2.0.0" + +"@dnd-kit/core@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@dnd-kit/core/-/core-6.1.0.tgz#e81a3d10d9eca5d3b01cbf054171273a3fe01def" + integrity sha512-J3cQBClB4TVxwGo3KEjssGEXNJqGVWx17aRTZ1ob0FliR5IjYgTxl5YJbKTzA6IzrtelotH19v6y7uoIRUZPSg== + dependencies: + "@dnd-kit/accessibility" "^3.1.0" + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/sortable@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@dnd-kit/sortable/-/sortable-8.0.0.tgz#086b7ac6723d4618a4ccb6f0227406d8a8862a96" + integrity sha512-U3jk5ebVXe1Lr7c2wU7SBZjcWdQP+j7peHJfCspnA81enlu88Mgd7CC8Q+pub9ubP7eKVETzJW+IBAhsqbSu/g== + dependencies: + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/utilities@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.2.tgz#5a32b6af356dc5f74d61b37d6f7129a4040ced7b" + integrity sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg== + dependencies: + tslib "^2.0.0" + +"@emotion/babel-plugin@^11.13.5": + version "11.13.5" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz#eab8d65dbded74e0ecfd28dc218e75607c4e7bc0" + integrity sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/serialize" "^1.3.3" + babel-plugin-macros "^3.1.0" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.2.0" + +"@emotion/cache@^11.13.5", "@emotion/cache@^11.14.0", "@emotion/cache@^11.4.0": + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.14.0.tgz#ee44b26986eeb93c8be82bb92f1f7a9b21b2ed76" + integrity sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA== + dependencies: + "@emotion/memoize" "^0.9.0" + "@emotion/sheet" "^1.4.0" + "@emotion/utils" "^1.4.2" + "@emotion/weak-memoize" "^0.4.0" + stylis "4.2.0" + +"@emotion/hash@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" + integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== + +"@emotion/is-prop-valid@^1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz#8d5cf1132f836d7adbe42cf0b49df7816fc88240" + integrity sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw== + dependencies: + "@emotion/memoize" "^0.9.0" + +"@emotion/memoize@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" + integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== + +"@emotion/react@^11.8.1": + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.14.0.tgz#cfaae35ebc67dd9ef4ea2e9acc6cd29e157dd05d" + integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.13.5" + "@emotion/cache" "^11.14.0" + "@emotion/serialize" "^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.2.0" + "@emotion/utils" "^1.4.2" + "@emotion/weak-memoize" "^0.4.0" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.3.tgz#d291531005f17d704d0463a032fe679f376509e8" + integrity sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA== + dependencies: + "@emotion/hash" "^0.9.2" + "@emotion/memoize" "^0.9.0" + "@emotion/unitless" "^0.10.0" + "@emotion/utils" "^1.4.2" + csstype "^3.0.2" + +"@emotion/sheet@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" + integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== + +"@emotion/styled@^11.14.0": + version "11.14.1" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.14.1.tgz#8c34bed2948e83e1980370305614c20955aacd1c" + integrity sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw== + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.13.5" + "@emotion/is-prop-valid" "^1.3.0" + "@emotion/serialize" "^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.2.0" + "@emotion/utils" "^1.4.2" + +"@emotion/unitless@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" + integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== + +"@emotion/use-insertion-effect-with-fallbacks@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz#8a8cb77b590e09affb960f4ff1e9a89e532738bf" + integrity sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg== + +"@emotion/utils@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.2.tgz#6df6c45881fcb1c412d6688a311a98b7f59c1b52" + integrity sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA== + +"@emotion/weak-memoize@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" + integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== + +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@floating-ui/core@^1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7" + integrity sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w== + dependencies: + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.0.1", "@floating-ui/dom@^1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.3.tgz#6174ac3409e6a064bbdf1f4bb07188ee9461f8cf" + integrity sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag== + dependencies: + "@floating-ui/core" "^1.7.3" + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/react-dom@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.2.tgz#a1349bbf6a0e5cb5ded55d023766f20a4d439a31" + integrity sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A== + dependencies: + "@floating-ui/dom" "^1.0.0" + +"@floating-ui/react-dom@^2.1.2": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.5.tgz#d11e3726d2eb385d8cf3216348742907c1d49fcf" + integrity sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q== + dependencies: + "@floating-ui/dom" "^1.7.3" + +"@floating-ui/react@0.26.24": + version "0.26.24" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.24.tgz#072b9dfeca4e79ef4e3000ef1c28e0ffc86f4ed4" + integrity sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw== + dependencies: + "@floating-ui/react-dom" "^2.1.2" + "@floating-ui/utils" "^0.2.8" + tabbable "^6.0.0" + +"@floating-ui/react@^0.26.2": + version "0.26.28" + resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.28.tgz#93f44ebaeb02409312e9df9507e83aab4a8c0dc7" + integrity sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw== + dependencies: + "@floating-ui/react-dom" "^2.1.2" + "@floating-ui/utils" "^0.2.8" + tabbable "^6.0.0" + +"@floating-ui/utils@^0.2.10", "@floating-ui/utils@^0.2.8": + version "0.2.10" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" + integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== + +"@formatjs/ecma402-abstract@2.3.4": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz#e90c5a846ba2b33d92bc400fdd709da588280fbc" + integrity sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA== + dependencies: + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/intl-localematcher" "0.6.1" + decimal.js "^10.4.3" + tslib "^2.8.0" + +"@formatjs/fast-memoize@2.2.7": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz#707f9ddaeb522a32f6715bb7950b0831f4cc7b15" + integrity sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ== + dependencies: + tslib "^2.8.0" + +"@formatjs/icu-messageformat-parser@2.11.2": + version "2.11.2" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz#85aea211bea40aa81ee1d44ac7accc3cf5500a73" + integrity sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/icu-skeleton-parser" "1.8.14" + tslib "^2.8.0" + +"@formatjs/icu-skeleton-parser@1.8.14": + version "1.8.14" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz#b9581d00363908efb29817fdffc32b79f41dabe5" + integrity sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + tslib "^2.8.0" + +"@formatjs/intl-localematcher@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz#25dc30675320bf65a9d7f73876fc1e4064c0e299" + integrity sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg== + dependencies: + tslib "^2.8.0" + +"@heroicons/react@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.5.tgz#1e13f34976cc542deae92353c01c8b3d7942e9ba" + integrity sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA== + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@internationalized/date@^3.8.2": + version "3.8.2" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.8.2.tgz#977620c1407cc6830fd44cb505679d23c599e119" + integrity sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA== + dependencies: + "@swc/helpers" "^0.5.0" + +"@internationalized/message@^3.1.8": + version "3.1.8" + resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.8.tgz#7181e8178f0868535f4507a573bf285e925832cb" + integrity sha512-Rwk3j/TlYZhn3HQ6PyXUV0XP9Uv42jqZGNegt0BXlxjE6G3+LwHjbQZAGHhCnCPdaA6Tvd3ma/7QzLlLkJxAWA== + dependencies: + "@swc/helpers" "^0.5.0" + intl-messageformat "^10.1.0" + +"@internationalized/number@^3.6.4": + version "3.6.4" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.4.tgz#3ab593fec5e87654fdece0a3238cdc9d0eedff8a" + integrity sha512-P+/h+RDaiX8EGt3shB9AYM1+QgkvHmJ5rKi4/59k4sg9g58k9rqsRW0WxRO7jCoHyvVbFRRFKmVTdFYdehrxHg== + dependencies: + "@swc/helpers" "^0.5.0" + +"@internationalized/string@^3.2.4", "@internationalized/string@^3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.7.tgz#76ae10f1e6e1fdaec7d0028a3f807d37a71bd2dd" + integrity sha512-D4OHBjrinH+PFZPvfCXvG28n2LSykWcJ7GIioQL+ok0LON15SdfoUssoHzzOUmVZLbRoREsQXVzA6r8JKsbP6A== + dependencies: + "@swc/helpers" "^0.5.0" + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + 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" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.12" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" + integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" + integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.29" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" + integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@lukeed/csprng@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" + integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA== + +"@lukeed/uuid@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@lukeed/uuid/-/uuid-2.0.1.tgz#4f6c34259ee0982a455e1797d56ac27bb040fd74" + integrity sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w== + dependencies: + "@lukeed/csprng" "^1.1.0" + +"@mui/core-downloads-tracker@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.18.0.tgz#85019a8704b0f63305fc5600635ee663810f2b66" + integrity sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA== + +"@mui/material@^5.15.10": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.18.0.tgz#71e72d52338252edc6f8d9461e04fdf0d61905cd" + integrity sha512-bbH/HaJZpFtXGvWg3TsBWG4eyt3gah3E7nCNU8GLyRjVoWcA91Vm/T+sjHfUcwgJSw9iLtucfHBoq+qW/T30aA== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/core-downloads-tracker" "^5.18.0" + "@mui/system" "^5.18.0" + "@mui/types" "~7.2.15" + "@mui/utils" "^5.17.1" + "@popperjs/core" "^2.11.8" + "@types/react-transition-group" "^4.4.10" + clsx "^2.1.0" + csstype "^3.1.3" + prop-types "^15.8.1" + react-is "^19.0.0" + react-transition-group "^4.4.5" + +"@mui/private-theming@^5.17.1": + version "5.17.1" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.17.1.tgz#b4b6fbece27830754ef78186e3f1307dca42f295" + integrity sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/utils" "^5.17.1" + prop-types "^15.8.1" + +"@mui/styled-engine@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.18.0.tgz#914cca1385bb33ce0cde31721f529c8bd7fa301c" + integrity sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg== + dependencies: + "@babel/runtime" "^7.23.9" + "@emotion/cache" "^11.13.5" + "@emotion/serialize" "^1.3.3" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/styled-engine@^7.1.0": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-7.3.1.tgz#c8fbfd5636376bf8ded8626a2423fdc53ede6343" + integrity sha512-Nqo6OHjvJpXJ1+9TekTE//+8RybgPQUKwns2Lh0sq+8rJOUSUKS3KALv4InSOdHhIM9Mdi8/L7LTF1/Ky6D6TQ== + dependencies: + "@babel/runtime" "^7.28.2" + "@emotion/cache" "^11.14.0" + "@emotion/serialize" "^1.3.3" + "@emotion/sheet" "^1.4.0" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/system@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.18.0.tgz#e55331203a40584b26c5a855a07949ac8973bfb6" + integrity sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/private-theming" "^5.17.1" + "@mui/styled-engine" "^5.18.0" + "@mui/types" "~7.2.15" + "@mui/utils" "^5.17.1" + clsx "^2.1.0" + csstype "^3.1.3" + prop-types "^15.8.1" + +"@mui/types@~7.2.15": + version "7.2.24" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.24.tgz#5eff63129d9c29d80bbf2d2e561bd0690314dec2" + integrity sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw== + +"@mui/utils@^5.17.1": + version "5.17.1" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.17.1.tgz#72ba4ffa79f7bdf69d67458139390f18484b6e6b" + integrity sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/types" "~7.2.15" + "@types/prop-types" "^15.7.12" + clsx "^2.1.1" + prop-types "^15.8.1" + react-is "^19.0.0" + +"@neo4j-bloom/dagre@^0.8.14": + version "0.8.14" + resolved "https://registry.yarnpkg.com/@neo4j-bloom/dagre/-/dagre-0.8.14.tgz#bad99d7ce4b73fc1c5f0926c1e4a505adcc9c681" + integrity sha512-FW1hbtbEr1FmJzGdbLxGOcn2SYZPhM1kGCs8RlMkqrjcXpcueTmEDZzGhZJx7KLbT15VSzEM6/sK4CaVsXdhkQ== + dependencies: + graphlib "2.1.8" + lodash "^4.17.19" + +"@neo4j-devtools/word-color@^0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@neo4j-devtools/word-color/-/word-color-0.0.8.tgz#48b181022659de01e251073e5967423fc922c053" + integrity sha512-0fC2PXU1M0wL72lVil/2JnUccpEoPaiNJsNAc8fgRUysVeZ/OLKFvZAeOnufJ4X5OKkImaL1lvoGyhfKfOKfzw== + dependencies: + "@types/chroma-js" "2.1.4" + chroma-js "2.4.2" + +"@neo4j-ndl/base@^3.2.9": + version "3.7.19" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-3.7.19.tgz#7a79b97ca89b9a111eb72a767c88b054be9bcc85" + integrity sha512-YXyO7VRppuwthxvRUTnfsr9uY9C7G0QHSTkqdVoBc/o7+AURxBf24nrHqbq2yhh6ba/cu/CZSwX3QdgXh47l6A== + +"@neo4j-ndl/react@^3.2.18": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-3.9.1.tgz#20a3a74fcccac897e89f92d8fb06fefee0752d03" + integrity sha512-fNRevCccg06mU9UaVZeQC/a9Tr6IFKrEAKkbjgenXTHo8zJlfn+w30fqHNgHfMMV/VUtnUuBi8M4fIVguvb/mw== + dependencies: + "@dnd-kit/core" "6.1.0" + "@dnd-kit/sortable" "8.0.0" + "@floating-ui/react" "0.26.24" + "@floating-ui/react-dom" "2.1.2" + "@heroicons/react" "2.1.5" + "@neo4j-devtools/word-color" "^0.0.8" + "@neo4j-nvl/base" "0.3.9" + "@neo4j-nvl/interaction-handlers" "0.3.9" + "@neo4j-nvl/react" "0.3.9" + "@uiw/react-color" "2.5.4" + classnames "2.5.1" + date-fns "4.1.0" + detect-browser "5.3.0" + eyedropper-polyfill "1.0.2" + re-resizable "6.11.2" + react-aria "3.35.0" + react-datepicker "6.9.0" + react-dropzone "14.2.9" + react-focus-lock "2.13.2" + react-select "5.9.0" + react-stately "3.33.0" + react-syntax-highlighter "15.5.0" + react-use "17.5.1" + sonner "1.7.1" + tinycolor2 "1.6.0" + usehooks-ts "3.1.0" + +"@neo4j-nvl/base@0.3.9", "@neo4j-nvl/base@^0.3.6": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/base/-/base-0.3.9.tgz#19b9832f4c2d011f781f12f652b9c54ac77f7326" + integrity sha512-tQsMb5X7tT8KzCkDqgbeSSMFDt6Fr7180zKCCS7ttwq9zIuN4+JbNyIJ6E7Z+Sd+2yDsWbC0pWWCKZje6U4Jrg== + dependencies: + "@neo4j-nvl/layout-workers" "0.3.9" + "@segment/analytics-next" "^1.70.0" + color-string "^1.9.1" + d3-force "^3.0.0" + gl-matrix "^3.3.0" + glsl-inject-defines "^1.0.3" + lodash "4.17.21" + loglevel "^1.8.0" + mobx "^3.2.2" + node-pid-controller "^1.0.1" + resizelistener "^1.1.0" + tinycolor2 "1.6.0" + uuid "^8.3.2" + +"@neo4j-nvl/interaction-handlers@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/interaction-handlers/-/interaction-handlers-0.3.9.tgz#412e68bbeb1a2b60b892be5e8ceb05ecbc1f88d8" + integrity sha512-rpPJEj6NWZJp7jqaVs//MQQd6q8jRhlDtJg0WSbcS3gXw+b98ODnVTqczw7ZeKpmmtZWc8dnvtApe5EleLrLwg== + dependencies: + "@neo4j-nvl/base" "0.3.9" + concaveman "^1.2.1" + lodash "4.17.21" + +"@neo4j-nvl/layout-workers@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/layout-workers/-/layout-workers-0.3.9.tgz#992cb1ad3a08f68f89e1eda820a59d9b4091eedd" + integrity sha512-3DHSL7Cb5Zcs3Aue5RmFaJsxTNXd5AILepwdyQFE0A/gEmVpmBMbJE2QnBGCOQhUXf3hpW3QGz8Z0DkZzhHPuw== + dependencies: + "@neo4j-bloom/dagre" "^0.8.14" + bin-pack "^1.0.2" + cytoscape "^3.23.0" + cytoscape-cose-bilkent "^4.1.0" + graphlib "^2.1.8" + +"@neo4j-nvl/react@0.3.9", "@neo4j-nvl/react@^0.3.8": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/react/-/react-0.3.9.tgz#086150940638ba6f421cbb4e0294e57538428bcb" + integrity sha512-ZSxv66MWPAm29YdvlSHEjbI81YxTh/brTT56HsNQOhDWqPl5ebcAaNXtx6l4AWpb2jsi6EPcGKf1kqblEWdbyg== + dependencies: + "@neo4j-nvl/base" "0.3.9" + "@neo4j-nvl/interaction-handlers" "0.3.9" + lodash "4.17.21" + react "^18.2.0" + react-dom "^18.2.0" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@popperjs/core@^2.11.8": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + +"@react-aria/breadcrumbs@^3.5.17": + version "3.5.27" + resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.27.tgz#594e6190518baa3da324a79e24a539e4a9606f6b" + integrity sha512-fuXD9nvBaBVZO0Z6EntBlxQD621/2Ldcxz76jFjc4V/jNOq/6BIVQRtpnAYYrSTiW3ZV2IoAyxRWNxQU22hOow== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/link" "^3.8.4" + "@react-aria/utils" "^3.30.0" + "@react-types/breadcrumbs" "^3.7.15" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/button@^3.10.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.14.0.tgz#3d0de54d9308812205c29e2294554a77bb8d6cea" + integrity sha512-we6z+2GpZO8lGD6EPmYH2S87kLCpU14D2E3tD2vES+SS2sZM2qcm2dUGpeo4+gZqBToLWKEBAGCSlkWEtgS19A== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/toolbar" "3.0.0-beta.19" + "@react-aria/utils" "^3.30.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/calendar@^3.5.12": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.9.0.tgz#6b5a80df82384e47ebcb8e8aed73ce706ff42efd" + integrity sha512-YxHLqL/LZrgwYGKzlQ96Fgt6gC+Q1L8k56sD51jJAtiD+YtT/pKJfK1zjZ3rtHtPTDYzosJ8vFgOmZNpnKQpXQ== + dependencies: + "@internationalized/date" "^3.8.2" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/calendar" "^3.8.3" + "@react-types/button" "^3.13.0" + "@react-types/calendar" "^3.7.3" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/checkbox@^3.14.7": + version "3.16.0" + resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.16.0.tgz#775b3c0bde40bcfa8ab28439ba896088ba489d1b" + integrity sha512-XPaMz1/iVBG6EbJOPYlNtvr+q4f0axJeoIvyzWW3ciIdDSX/3jYuFg/sv/b3OQQl389cbQ/WUBQyWre/uXWVEg== + dependencies: + "@react-aria/form" "^3.1.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/toggle" "^3.12.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/checkbox" "^3.7.0" + "@react-stately/form" "^3.2.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/color@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.1.0.tgz#d131deef07ef66881e1dad4ed9d4e4f41b5242bc" + integrity sha512-95qcCmz5Ss6o1Z4Z7X3pEEQxoUA83qGNQkpjOvobcHbNWKfhvOAsUzdBleOx2NpyBzY16OAnhWR7PJZwR4AqiA== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/numberfield" "^3.12.0" + "@react-aria/slider" "^3.8.0" + "@react-aria/spinbutton" "^3.6.17" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/color" "^3.9.0" + "@react-stately/form" "^3.2.0" + "@react-types/color" "^3.1.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/combobox@^3.10.4": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.13.0.tgz#b89b26553ee0b63ff35c51b3e214c55d076a5bf4" + integrity sha512-eBa8aWcL3Ar/BvgSaqYDmNQP70LPZ7us2myM31QQt2YDRptqGHd44wzXCts9SaDVIeMVy+AEY2NkuxrVE6yNrw== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/listbox" "^3.14.7" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/menu" "^3.19.0" + "@react-aria/overlays" "^3.28.0" + "@react-aria/selection" "^3.25.0" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/combobox" "^3.11.0" + "@react-stately/form" "^3.2.0" + "@react-types/button" "^3.13.0" + "@react-types/combobox" "^3.13.7" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/datepicker@^3.11.3": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.15.0.tgz#b110e35189dad1fd6008c2a271bf03624a0959b3" + integrity sha512-AONeLj7sMKz4JmzCu4bhsqwcNFXCSWoaBhi4wOJO9+WYmxudn5mSI9ez8NMCVn+s5kcYpyvzrrAFf/DvQ4UDgw== + dependencies: + "@internationalized/date" "^3.8.2" + "@internationalized/number" "^3.6.4" + "@internationalized/string" "^3.2.7" + "@react-aria/focus" "^3.21.0" + "@react-aria/form" "^3.1.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/spinbutton" "^3.6.17" + "@react-aria/utils" "^3.30.0" + "@react-stately/datepicker" "^3.15.0" + "@react-stately/form" "^3.2.0" + "@react-types/button" "^3.13.0" + "@react-types/calendar" "^3.7.3" + "@react-types/datepicker" "^3.13.0" + "@react-types/dialog" "^3.5.20" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/dialog@^3.5.18": + version "3.5.28" + resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.28.tgz#0cc8dcec8399d17baa65f4a325e65c3a93f0a5e1" + integrity sha512-S9dgdFBQc9LbhyBiHwGPSATwtvsIl6h+UnxDJ4oKBSse+wxdAyshbZv2tyO5RFbe3k73SAgU7yKocfg7YyRM0A== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/overlays" "^3.28.0" + "@react-aria/utils" "^3.30.0" + "@react-types/dialog" "^3.5.20" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/dnd@^3.7.3": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.11.0.tgz#5f945ed7ad0bb5faf49d700d93c603049e112a64" + integrity sha512-jr47o7Fy55eYjSKWqRyuWKPnynpgC4cE9YXnYg5xa+1woRefIF2IyteOxgSHeX16+6ef2UDSsvC61T3gS6NWxQ== + dependencies: + "@internationalized/string" "^3.2.7" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/overlays" "^3.28.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/dnd" "^3.6.1" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/focus@^3.18.3", "@react-aria/focus@^3.21.0": + version "3.21.0" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.21.0.tgz#d5bc327bee25e981934ea0ddb1defbe020a84f6a" + integrity sha512-7NEGtTPsBy52EZ/ToVKCu0HSelE3kq9qeis+2eEq90XSuJOMaDHUQrA7RC2Y89tlEwQB31bud/kKRi9Qme1dkA== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + clsx "^2.0.0" + +"@react-aria/form@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.1.0.tgz#78961c7884e561f1a389cd10d94a069fc4455e83" + integrity sha512-aDAOZafrn0V8e09mDAtCvc+JnpnkFM9X8cbI5+fdXsXAA+JxO+3uRRfnJHBlIL0iLc4C4OVWxBxWToV95pg1KA== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/form" "^3.2.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/grid@^3.14.3": + version "3.14.3" + resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.14.3.tgz#660a54b78e3c0b75d5330752c21de8b2f69a1133" + integrity sha512-O4Ius5tJqKcMGfQT6IXD4MnEOeq6f/59nKmfCLTXMREFac/oxafqanUx3zrEVYbaqLOjEmONcd8S61ptQM6aPg== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/grid" "^3.11.4" + "@react-stately/selection" "^3.20.4" + "@react-types/checkbox" "^3.10.0" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/gridlist@^3.13.3", "@react-aria/gridlist@^3.9.4": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.13.3.tgz#b90ec98839ec5b631825c45e4cad021e941b2b6f" + integrity sha512-U2x/1MpdrAgK/vay2s2nVSko4WysajlMS+L8c18HE/ig2to+C8tCPWH2UuK4jTQWrK5x/PxTH+/yvtytljnIuQ== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/grid" "^3.14.3" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/list" "^3.12.4" + "@react-stately/tree" "^3.9.1" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/i18n@^3.12.11", "@react-aria/i18n@^3.12.3": + version "3.12.11" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.11.tgz#839b98baf8b298ccc76b98c5d3ba3a889f61baf7" + integrity sha512-1mxUinHbGJ6nJ/uSl62dl48vdZfWTBZePNF/wWQy98gR0qNFXLeusd7CsEmJT1971CR5i/WNYUo1ezNlIJnu6A== + dependencies: + "@internationalized/date" "^3.8.2" + "@internationalized/message" "^3.1.8" + "@internationalized/number" "^3.6.4" + "@internationalized/string" "^3.2.7" + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/interactions@^3.22.3", "@react-aria/interactions@^3.25.4": + version "3.25.4" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.25.4.tgz#2f0e21e8187b7f0944b323f55696cae9accb39e0" + integrity sha512-HBQMxgUPHrW8V63u9uGgBymkMfj6vdWbB0GgUJY49K9mBKMsypcHeWkWM6+bF7kxRO728/IK8bWDV6whDbqjHg== + dependencies: + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.30.0" + "@react-stately/flags" "^3.1.2" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/label@^3.7.12", "@react-aria/label@^3.7.20": + version "3.7.20" + resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.20.tgz#3e2a6d887588166fd98fc66e6d3fc2ebeaa59d3a" + integrity sha512-Hw7OsC2GBnjptyW1lC1+SNoSIZA0eIh02QnNDr1XX2S+BPfn958NxoI7sJIstO/TUpQVNqdjEN/NI6+cyuJE6g== + dependencies: + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/link@^3.7.5", "@react-aria/link@^3.8.4": + version "3.8.4" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.8.4.tgz#43ca9c9d82b84e157f7b25048c61f9b87328e87a" + integrity sha512-7cPRGIo7x6ZZv1dhp2xGjqLR1snazSQgl7tThrBDL5E8f6Yr7SVpxOOK5/EBmfpFkhkmmXEO/Fgo/GPJdc6Vmw== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-types/link" "^3.6.3" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/listbox@^3.13.4", "@react-aria/listbox@^3.14.7": + version "3.14.7" + resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.14.7.tgz#079d40dc29f2601d4ceb894a9de0715e55e9c70f" + integrity sha512-U5a+AIDblaeQTIA1MDFUaYIKoPwPNAuY7SwkuA5Z7ClDOeQJkiyExmAoKcUXwUkrLULQcbOPKr401q38IL3T7Q== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/list" "^3.12.4" + "@react-types/listbox" "^3.7.2" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/live-announcer@^3.4.4": + version "3.4.4" + resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.4.tgz#0e6533940222208b323b71d56ac8e115b2121e6a" + integrity sha512-PTTBIjNRnrdJOIRTDGNifY2d//kA7GUAwRFJNOEwSNG4FW+Bq9awqLiflw0JkpyB0VNIwou6lqKPHZVLsGWOXA== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-aria/menu@^3.15.4", "@react-aria/menu@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.19.0.tgz#a53d5506545131fbfa4e6848eb7b4fdadec69947" + integrity sha512-VLUGbZedKJvK2OFWEpa86GPIaj9QcWox/R9JXmNk6nyrAz/V46OBQENdliV26PEdBZgzrVxGvmkjaH7ZsN/32Q== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/overlays" "^3.28.0" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/menu" "^3.9.6" + "@react-stately/selection" "^3.20.4" + "@react-stately/tree" "^3.9.1" + "@react-types/button" "^3.13.0" + "@react-types/menu" "^3.10.3" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/meter@^3.4.17": + version "3.4.25" + resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.25.tgz#f0bb2b10ffd47155257a0a23a1ea0b9ad52e7828" + integrity sha512-6IqOnwuEt8z6UDy8Ru3ZZRZIUiELD0N3Wi/udMfR8gz4oznutvnRCMpRXkVVaVLYQfRglybu2/Lxfe+rq8WiRg== + dependencies: + "@react-aria/progress" "^3.4.25" + "@react-types/meter" "^3.4.11" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/numberfield@^3.11.7", "@react-aria/numberfield@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.12.0.tgz#e17ae9212d230ecb96c698d544561d0355862754" + integrity sha512-JkgkjYsZ9lN5m3//X3buOKVrA/QJEeeXJ+5T5r6AmF29YdIhD1Plf5AEOWoRpZWQ25chH7FI/Orsf4h3/SLOpg== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/spinbutton" "^3.6.17" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/form" "^3.2.0" + "@react-stately/numberfield" "^3.10.0" + "@react-types/button" "^3.13.0" + "@react-types/numberfield" "^3.8.13" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/overlays@^3.23.3", "@react-aria/overlays@^3.28.0": + version "3.28.0" + resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.28.0.tgz#152d97b34b0ccab4fc53b1ae4bbf229c937ed6d6" + integrity sha512-qaHahAXTmxXULgg2/UfWEIwfgdKsn27XYryXAWWDu2CAZTcbI+5mGwYrQZSDWraM6v5PUUepzOVvm7hjTqiMFw== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/overlays" "^3.6.18" + "@react-types/button" "^3.13.0" + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/progress@^3.4.17", "@react-aria/progress@^3.4.25": + version "3.4.25" + resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.25.tgz#ff33ee73bb3ac4f04a711b02c3b85710693379bb" + integrity sha512-KD9Gow+Ip6ZCBdsarR+Hby3c4d99I6L95Ruf7tbCh4ut9i9Dbr+x99OwhpAbT0g549cOyeIqxutPkT+JuzrRuA== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-types/progress" "^3.5.14" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/radio@^3.10.8": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.12.0.tgz#fc32e49b3c791b5c2100ab6911a075c67c2aa1e3" + integrity sha512-//0zZUuHtbm6uZR9+sNRNzVcQpjJKjZj57bDD0lMNj3NZp/Tkw+zXIFy6j1adv3JMe6iYkzEgaB7YRDD1Fe/ZA== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/form" "^3.1.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-stately/radio" "^3.11.0" + "@react-types/radio" "^3.9.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/searchfield@^3.7.9": + version "3.8.7" + resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.8.7.tgz#f45c7ec2a1ac24f607d353c69f27ba3aa20ea45a" + integrity sha512-15jfALRyz5EAA5tvIELVfUlqTFdk8oG442OiS3Xq/jJij8uKRzwUdnL57EVTFYyg+VMLp/t5wX+obXYcRG+kdQ== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/searchfield" "^3.5.14" + "@react-types/button" "^3.13.0" + "@react-types/searchfield" "^3.6.4" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/select@^3.14.10": + version "3.16.0" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.16.0.tgz#cc3343733514a3fc271b91f3916b3f598ece695c" + integrity sha512-UkiLSxMOKWW24qnhZdOObkFLpauvmu0T6wuPXbdQgwlis/UeLzDamPAWc6loRFJgHCpJftaaaWVQG3ks4NX7ew== + dependencies: + "@react-aria/form" "^3.1.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/listbox" "^3.14.7" + "@react-aria/menu" "^3.19.0" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/select" "^3.7.0" + "@react-types/button" "^3.13.0" + "@react-types/select" "^3.10.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/selection@^3.20.0", "@react-aria/selection@^3.25.0": + version "3.25.0" + resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.25.0.tgz#f284a4ad9820dd2c01bc69c8670c2032021136e0" + integrity sha512-Q3U0Ya0PTP/TR0a2g+7YEbFVLphiWthmEkHyvOx9HsKSjE8w9wXY3C14DZWKskB/BBrXKJuOWxBDa0xhC83S+A== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/selection" "^3.20.4" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/separator@^3.4.3": + version "3.4.11" + resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.11.tgz#ec63787ccc2f9d583098af35ba02e895cd2bfbe5" + integrity sha512-WwYEb7Wga4YQvlEwbzlVcVkfByullcORKtIe30pmh1YkTRRVJhbRPaE/mwcSMufbfjSYdtDavxmF+WY7Tdb9/A== + dependencies: + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/slider@^3.7.12", "@react-aria/slider@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.8.0.tgz#9535c2782ab7a2fb6a5d0497caa77a572ae70b81" + integrity sha512-D7Sa7q21cV3gBid7frjoYw6924qYqNdJn2oai1BEemHSuwQatRlm1o2j+fnPTy9sYZfNOqXYnv5YjEn0o1T+Gw== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-stately/slider" "^3.7.0" + "@react-types/shared" "^3.31.0" + "@react-types/slider" "^3.8.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/spinbutton@^3.6.17": + version "3.6.17" + resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.17.tgz#5b1f79389e176519923515cb987587990287b005" + integrity sha512-gdGc3kkqpvFUd9XsrhPwQHMrG2TY0LVuGGgjvaZwF/ONm9FMz393ogCM0P484HsjU50hClO+yiRRgNjdwDIzPQ== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.30.0" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/ssr@^3.9.10", "@react-aria/ssr@^3.9.6": + version "3.9.10" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.10.tgz#7fdc09e811944ce0df1d7e713de1449abd7435e6" + integrity sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-aria/switch@^3.6.8": + version "3.7.6" + resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.7.6.tgz#fe250201f17e7201ef3bb78a0979241506ebcea5" + integrity sha512-C+Od8hZNZCf3thgtZnZKzHl5b/63Q9xf+Pw6ugLA1qaKazwp46x1EwUVVqVhfAeVhmag++eHs8Lol5ZwQEinjQ== + dependencies: + "@react-aria/toggle" "^3.12.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/shared" "^3.31.0" + "@react-types/switch" "^3.5.13" + "@swc/helpers" "^0.5.0" + +"@react-aria/table@^3.15.4": + version "3.17.6" + resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.17.6.tgz#dc2d645112434371cb50b1a9bcfbfb00f0a49a49" + integrity sha512-PSEaeKOIazVEaykeTLudPbDLytJgOPLZJalS/xXY0/KL+Gi0Olchmz4tvS0WBe87ChmlVi6GQqU+stk23aZVWg== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/grid" "^3.14.3" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/collections" "^3.12.6" + "@react-stately/flags" "^3.1.2" + "@react-stately/table" "^3.14.4" + "@react-types/checkbox" "^3.10.0" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" + "@react-types/table" "^3.13.2" + "@swc/helpers" "^0.5.0" + +"@react-aria/tabs@^3.9.6": + version "3.10.6" + resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.10.6.tgz#d2a78cd6b7bca78c60a01cb0e8b2b8230514f614" + integrity sha512-L8MaE7+bu6ByDOUxNPpMMYxdHULhKUfBoXdsSsXqb1z3QxdFW2zovfag0dvpyVWB6ALghX2T0PlTUNqaKA5tGw== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/tabs" "^3.8.4" + "@react-types/shared" "^3.31.0" + "@react-types/tabs" "^3.3.17" + "@swc/helpers" "^0.5.0" + +"@react-aria/tag@^3.4.6": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.7.0.tgz#c34c97842607f0de5c936823e42945de2e6339dd" + integrity sha512-nU0Sl7u82RBn8XLNyrjkXhtw+xbJD9fyjesmDu7zeOq78e4eunKW7OZ/9+t+Lyu5wW+B7vKvetIgkdXKPQm3MA== + dependencies: + "@react-aria/gridlist" "^3.13.3" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/list" "^3.12.4" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/textfield@^3.14.9", "@react-aria/textfield@^3.18.0": + version "3.18.0" + resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.18.0.tgz#fc5e4742559b53b8ec0a5037337743506a6c8071" + integrity sha512-kCwbyDHi2tRaD/OjagA3m3q2mMZUPeXY7hRqhDxpl2MwyIdd+/PQOJLM8tZr5+m2zvBx+ffOcjZMGTMwMtoV5w== + dependencies: + "@react-aria/form" "^3.1.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@react-types/textfield" "^3.12.4" + "@swc/helpers" "^0.5.0" + +"@react-aria/toggle@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.12.0.tgz#93e4037be4f52b3b8cf5e4f1e087184cf1afda4b" + integrity sha512-JfcrF8xUEa2CbbUXp+WQiTBVwSM/dm21v5kueQlksvLfXG6DGE8/zjM6tJFErrFypAasc1JXyrI4dspLOWCfRA== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/toolbar@3.0.0-beta.19": + version "3.0.0-beta.19" + resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.19.tgz#695b165ff0285be32e70b532e7d5b8e17da8dec1" + integrity sha512-G4sgtOUTUUJHznXlpKcY64SxD2gKOqIQXZXjWTVcY/Q5hAjl8gbTt5XIED22GmeIgd/tVl6+lddGj6ESze4vSg== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/tooltip@^3.7.8": + version "3.8.6" + resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.8.6.tgz#35818591795e464647efe71e595f4f407d21837e" + integrity sha512-lW/PegiswGLlCP0CM4FH2kbIrEe4Li2SoklzIRh4nXZtiLIexswoE5/5af7PMtoMAl31or6fHZleVLzZD4VcfA== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/tooltip" "^3.5.6" + "@react-types/shared" "^3.31.0" + "@react-types/tooltip" "^3.4.19" + "@swc/helpers" "^0.5.0" + +"@react-aria/utils@^3.25.3", "@react-aria/utils@^3.30.0": + version "3.30.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.30.0.tgz#68aa1d703c9e0468350bd1e3b583d99e9e69795a" + integrity sha512-ydA6y5G1+gbem3Va2nczj/0G0W7/jUVo/cbN10WA5IizzWIwMP5qhFr7macgbKfHMkZ+YZC3oXnt2NNre5odKw== + dependencies: + "@react-aria/ssr" "^3.9.10" + "@react-stately/flags" "^3.1.2" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + clsx "^2.0.0" + +"@react-aria/visually-hidden@^3.8.16", "@react-aria/visually-hidden@^3.8.26": + version "3.8.26" + resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.26.tgz#38d8432bc8609c33754ddeb5d279f54c473b2afd" + integrity sha512-Lz36lTVaQbv5Kn74sPv0l9SnLQ5XHKCoq2zilP14Eb4QixDIqR7Ovj43m+6wi9pynf29jtOb/8D/9jrTjbmmgw== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/calendar@^3.5.5", "@react-stately/calendar@^3.8.3": + version "3.8.3" + resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.8.3.tgz#749d8965d3825fdffd4b728b69fbd4c5099e667d" + integrity sha512-HTWD6ZKQcXDlvj6glEEG0oi2Tpkaw19y5rK526s04zJs894wFqM9PK0WHthEYqjCeQJ5B/OkyG19XX4lENxnZw== + dependencies: + "@internationalized/date" "^3.8.2" + "@react-stately/utils" "^3.10.8" + "@react-types/calendar" "^3.7.3" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/checkbox@^3.6.9", "@react-stately/checkbox@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.7.0.tgz#4464adc16148885a3a8e7fbdfb94eace75ee5887" + integrity sha512-opViVhNvxFVHjXhM4nA/E03uvbLazsIKloXX9JtyBCZAQRUag17dpmkekfIkHvP4o7z7AWFoibD8JBFV1IrMcQ== + dependencies: + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/collections@^3.11.0", "@react-stately/collections@^3.12.6": + version "3.12.6" + resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.12.6.tgz#0d8b6d2744dd0c29d31842d39a112d30c27a4387" + integrity sha512-S158RKWGZSodbJXKZDdcnrLzFxzFmyRWDNakQd1nBGhSrW2JV8lDn9ku5Og7TrjoEpkz//B2oId648YT792ilw== + dependencies: + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/color@^3.8.0", "@react-stately/color@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.9.0.tgz#9233c4d04d1794d0cb34b5687bca5edca7e7f1e6" + integrity sha512-9eG0gDxVIu+A+DTdfwyYuU4pR788pVdq1Snpk8el787OsOb5WiuT4C4VWJb5Qbrq2PiFhhZmxuJXpzz4B1gW3A== + dependencies: + "@internationalized/number" "^3.6.4" + "@internationalized/string" "^3.2.7" + "@react-stately/form" "^3.2.0" + "@react-stately/numberfield" "^3.10.0" + "@react-stately/slider" "^3.7.0" + "@react-stately/utils" "^3.10.8" + "@react-types/color" "^3.1.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/combobox@^3.10.0", "@react-stately/combobox@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.11.0.tgz#c8e647bedf747c14c6c91b136a0dc551d20a22a5" + integrity sha512-W9COXdSOC+uqCZrRHJI0K7emlPb/Tx4A89JHWBcFmiAk+hs1Cnlyjw3aaqEiT8A8/HxDNMO9QcfisWC1iNyE9A== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/form" "^3.2.0" + "@react-stately/list" "^3.12.4" + "@react-stately/overlays" "^3.6.18" + "@react-stately/select" "^3.7.0" + "@react-stately/utils" "^3.10.8" + "@react-types/combobox" "^3.13.7" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/data@^3.11.7": + version "3.13.2" + resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.13.2.tgz#b649aa85c58e0e20e257fc749daa8042b7d482fb" + integrity sha512-xdCqR8dJ3cnvO8EdCeuQ335dOuBqEV4z/3LnpxmR11gyn8dWwtY5O794g5+AS0KqCgd9W0v7iBrRywq5UT2pCA== + dependencies: + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/datepicker@^3.10.3", "@react-stately/datepicker@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.15.0.tgz#a152219bb362d2d81169e6ef4a12df988f93efe8" + integrity sha512-OuBx+h802CoANy6KNR6XuZCndiyRf9vpB32CYZX86nqWy21GSTeT73G41ze5cAH88A/6zmtpYK24nTlk8bdfWA== + dependencies: + "@internationalized/date" "^3.8.2" + "@internationalized/string" "^3.2.7" + "@react-stately/form" "^3.2.0" + "@react-stately/overlays" "^3.6.18" + "@react-stately/utils" "^3.10.8" + "@react-types/datepicker" "^3.13.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/dnd@^3.4.3", "@react-stately/dnd@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.6.1.tgz#409ba99b653cf7cdd140f8e582f11d911114178e" + integrity sha512-cbBLptL+tpXFQ0oU0v6GBtSvzP0doohyhCIr8pOzk6aYutFI0c5JZw8LGoKN/GLfXkm7iPyrfCKeKqDlDTHCzQ== + dependencies: + "@react-stately/selection" "^3.20.4" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/flags@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.1.2.tgz#5c8e5ae416d37d37e2e583d2fcb3a046293504f2" + integrity sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-stately/form@^3.0.6", "@react-stately/form@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.2.0.tgz#77b4030a9100a50f3e322c277783a4c0740948f1" + integrity sha512-PfefxvT7/BIhAGpD4oQpdcxnL8cfN0ZTQxQq+Wmb9z3YzK1oM8GFxb8eGdDRG71JeF8WUNMAQVZFhgl00Z/YKg== + dependencies: + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/grid@^3.11.4": + version "3.11.4" + resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.11.4.tgz#ec5eac6a8641d175ebef0f57c666af2cb18dad1f" + integrity sha512-oaXFSk2eM0PJ0GVniGA0ZlTpAA0AL0O4MQ7V3cHqZAQbwSO0n2pT31GM0bSVnYP/qTF5lQHo3ECmRQCz0fVyMw== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/selection" "^3.20.4" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/list@^3.11.0", "@react-stately/list@^3.12.4": + version "3.12.4" + resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.12.4.tgz#0515247773f1e8c314137c2883f7d95eeb2a7957" + integrity sha512-r7vMM//tpmagyNlRzl2NFPPtx+az5R9pM6q7aI4aBf6/zpZt2eX2UW5gaDTGlkQng7r6OGyAgJD52jmGcCJk7Q== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/selection" "^3.20.4" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/menu@^3.8.3", "@react-stately/menu@^3.9.6": + version "3.9.6" + resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.9.6.tgz#5f478f2e2f4dedce30e935f95eae0251b5790e3f" + integrity sha512-2rVtgeVAiyr7qL8BhmCK/4el49rna/5kADRH5NfPdpXw8ZzaiiHq2RtX443Txj7pUU82CJWQn+CRobq7k6ZTEw== + dependencies: + "@react-stately/overlays" "^3.6.18" + "@react-types/menu" "^3.10.3" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/numberfield@^3.10.0", "@react-stately/numberfield@^3.9.7": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.10.0.tgz#f6b54e308ec0a9dca51892d1b670b56bbf88e435" + integrity sha512-6C8ML4/e2tcn01BRNfFLxetVaWwz0n0pVROnVpo8p761c6lmTqohqEMNcXCVNw9H0wsa1hug2a1S5PcN2OXgag== + dependencies: + "@internationalized/number" "^3.6.4" + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/numberfield" "^3.8.13" + "@swc/helpers" "^0.5.0" + +"@react-stately/overlays@^3.6.11", "@react-stately/overlays@^3.6.18": + version "3.6.18" + resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.18.tgz#d2a4f013c84e0e93654afc26bbaeac67f28e9f8f" + integrity sha512-g8n2FtDCxIg2wQ09R7lrM2niuxMPCdP17bxsPV9hyYnN6m42aAKGOhzWrFOK+3phQKgk/E1JQZEvKw1cyyGo1A== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/overlays" "^3.9.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/radio@^3.10.8", "@react-stately/radio@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.11.0.tgz#42130406a5d27ca021ddb95ff12e3530315718fe" + integrity sha512-hsCmKb9e/ygmzBADFYIGpEQ43LrxjWnlKESgxphvlv0Klla4d6XLAYSFOTX1kcjSztpvVWrdl4cIfmKVF1pz2g== + dependencies: + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/radio" "^3.9.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/searchfield@^3.5.14", "@react-stately/searchfield@^3.5.7": + version "3.5.14" + resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.14.tgz#2887cd04bbd7c6e11087b71e75c3affbefc7f1bf" + integrity sha512-OAycTULyF/UWy7Odyzw5lZV2yWH+Cy7fWsZxDUedeUs4Aiwbb6D4ph9pGb0RvhD4S3+B490a2ijGgfsaDeorMA== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/searchfield" "^3.6.4" + "@swc/helpers" "^0.5.0" + +"@react-stately/select@^3.6.8", "@react-stately/select@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.7.0.tgz#0fec2feeb6d52898590e7a8cf024650e13889f13" + integrity sha512-OWLOCKBEj8/XI+vzBSSHQAJu0Hf9Xl/flMhYh47f2b45bO++DRLcVsi8nycPNisudvK6xMQ8a/h4FwjePrCXfg== + dependencies: + "@react-stately/form" "^3.2.0" + "@react-stately/list" "^3.12.4" + "@react-stately/overlays" "^3.6.18" + "@react-types/select" "^3.10.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/selection@^3.17.0", "@react-stately/selection@^3.20.4": + version "3.20.4" + resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.20.4.tgz#3bebfd5c6d4d27757531094a645dc8a3fa807f1b" + integrity sha512-Hxmc6NtECStYo+Z2uBRhQ80KPhbSF7xXv9eb4qN8dhyuSnsD6c0wc6oAJsv18dldcFz8VrD48aP/uff9mj0hxQ== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/slider@^3.5.8", "@react-stately/slider@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.7.0.tgz#64a5b3f3aa5ad961c45f18de12ed46eda9235716" + integrity sha512-quxqkyyxrxLELYEkPrIrucpVPdYDK8yyliv/vvNuHrjuLRIvx6UmssxqESp2EpZfwPYtEB29QXbAKT9+KuXoCQ== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@react-types/slider" "^3.8.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/table@^3.12.3", "@react-stately/table@^3.14.4": + version "3.14.4" + resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.14.4.tgz#d12eb43bcdcebc0f6b07e26abc19f3330b8dd31a" + integrity sha512-uhwk8z3DemozD+yHBjSa4WyxKczpDkxhJhW7ZVOY+1jNuTYxc9/JxzPsHICrlDVV8EPWwwyMUz8eO/8rKN7DbA== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/flags" "^3.1.2" + "@react-stately/grid" "^3.11.4" + "@react-stately/selection" "^3.20.4" + "@react-stately/utils" "^3.10.8" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" + "@react-types/table" "^3.13.2" + "@swc/helpers" "^0.5.0" + +"@react-stately/tabs@^3.6.10", "@react-stately/tabs@^3.8.4": + version "3.8.4" + resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.8.4.tgz#c9bd860ed98320502eda48e60a8c603f35f0f213" + integrity sha512-2Tr4yXkcNDLyyxrZr+c4FnAW/wkSim3UhDUWoOgTCy3mwlQzdh9r5qJrOZRghn1QvF7p8Ahp7O7qxwd2ZGJrvQ== + dependencies: + "@react-stately/list" "^3.12.4" + "@react-types/shared" "^3.31.0" + "@react-types/tabs" "^3.3.17" + "@swc/helpers" "^0.5.0" + +"@react-stately/toggle@^3.7.8", "@react-stately/toggle@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.9.0.tgz#f32db5d0ad5cb382add52a77a9025ce3fdf10fd8" + integrity sha512-1URd97R5nbFF9Hc1nQBhvln55EnOkLNz6pjtXU7TCnV4tYVbe+tc++hgr5XRt6KAfmuXxVDujlzRc6QjfCn0cQ== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/tooltip@^3.4.13", "@react-stately/tooltip@^3.5.6": + version "3.5.6" + resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.5.6.tgz#cb0c23f089a5ba740132b33a2148c92c1567a449" + integrity sha512-BnOtE7726t1sCKPGbwzzEtEx40tjpbJvw5yqpoVnAV0OLfrXtLVYfd7tWRHmZOYmhELaUnY+gm3ZFYtwvnjs+A== + dependencies: + "@react-stately/overlays" "^3.6.18" + "@react-types/tooltip" "^3.4.19" + "@swc/helpers" "^0.5.0" + +"@react-stately/tree@^3.8.5", "@react-stately/tree@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.9.1.tgz#17498b0832338f9aba82aebcb9e359df8b7680fc" + integrity sha512-dyoPIvPK/cs03Tg/MQSODi2kKYW1zaiOG9KC2P0c8b44mywU2ojBKzhSJky3dBkJ4VVGy7L+voBh50ELMjEa8Q== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/selection" "^3.20.4" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/utils@^3.10.8": + version "3.10.8" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.8.tgz#fdb9d172f7bbc2d083e69190f5ef0edfa4b4392f" + integrity sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-types/breadcrumbs@^3.7.15": + version "3.7.15" + resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.15.tgz#2b8b21aec32d2e328a4fa8b00f04f12908f6fed1" + integrity sha512-0RsymrsOAsx443XRDJ1krK+Lusr4t0qqExmzFe7/XYXOn/RbGKjzSdezsoWfTy8Hjks0YbfQPVKnNxg9LKv4XA== + dependencies: + "@react-types/link" "^3.6.3" + "@react-types/shared" "^3.31.0" + +"@react-types/button@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.13.0.tgz#a92ce8faa26bb27c7b44480b20dd35d732eaec4a" + integrity sha512-hwvcNnBjDeNvWheWfBhmkJSzC48ub5rZq0DnpemB3XKOvv5WcF9p6rrQZsQ3egNGkh0Z+bKfr2QfotgOkccHSw== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/calendar@^3.7.3": + version "3.7.3" + resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.7.3.tgz#7850b45054aece3ac2303be2126c10078fd9c70f" + integrity sha512-gofPgVpSawJ0iGO01SbVH46u3gdykHlGT5BfGU1cRnsOR2tJX38dekO/rnuGsMQYF0+kU6U9YVae+XoOFJNnWg== + dependencies: + "@internationalized/date" "^3.8.2" + "@react-types/shared" "^3.31.0" + +"@react-types/checkbox@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.10.0.tgz#999933ee1b81feea80d2d9f2d0685be248cb5127" + integrity sha512-DJ84ilBDvZddE/Sul97Otee4M6psrPRaJm2a1Bc7M3Y5UKo6d6RGXdcDarRRpbnS7BeAbVanKiMS2ygI9QHh9g== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/color@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.1.0.tgz#20d6246b6f4fd3d0f483f16ed45822aed7b3b570" + integrity sha512-mqx76zdq/GyI7hdx+NTdTrCG6qmf1Uk3w/zWKF80OAesLqqs9XavQQZlRPu1Cg/fHiAHIBOLYTnLf8w+T2IMsw== + dependencies: + "@react-types/shared" "^3.31.0" + "@react-types/slider" "^3.8.0" + +"@react-types/combobox@^3.13.7": + version "3.13.7" + resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.7.tgz#ff050e930f44c6b0ad188885334f26fe00db634c" + integrity sha512-R7MQ4Qm4fryo6FCg3Vo/l9wxkYVG05trsLbxzMvvxCMkpcoHUPhy8Ll33eXA3YP74Rs/IaM9d0d/amSUZ4M9wg== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/datepicker@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.13.0.tgz#18a826e0c96f25ccc1a9d891c92408a2d6ab931e" + integrity sha512-AG/iGcdQ5SVSjw8Ta7bCdGNkMda+e+Z7lOHxDawL44SII8LtZroBDlaCpb178Tvo17bBfJ6TvWXlvSpBY8GPRg== + dependencies: + "@internationalized/date" "^3.8.2" + "@react-types/calendar" "^3.7.3" + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" + +"@react-types/dialog@^3.5.20": + version "3.5.20" + resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.20.tgz#195391fdb98d433370927d69fdbff4dc9006a8e6" + integrity sha512-ebn8jW/xW/nmRATaWIPHVBIpIFWSaqjrAxa58f5TXer5FtCD9pUuzAQDmy/o22ucB0yvn6Kl+fjb3SMbMdALZQ== + dependencies: + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" + +"@react-types/grid@^3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.3.4.tgz#02f196995a585e650ab9a4d569e20635ba0ddb30" + integrity sha512-8XNn7Czhl+D1b2zRwdO8c3oBJmKgevT/viKJB4qBVFOhK0l/p3HYDZUMdeclvUfSt4wx4ASpI7MD3v1vmN54oA== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/link@^3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.6.3.tgz#ba223e8a2478c17d344dc286ac7a7a92dc1137d0" + integrity sha512-XIYEl9ZPa5mLy8uGQabdhPaFVmnvxNSYF59t0vs/IV0yxeoPvrjKjRAbXS+WP9zYMXIkHYNYYucriCkqKhotJA== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/listbox@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.7.2.tgz#36d7b1dcad36814d3f16abcc8ec6889b78934856" + integrity sha512-MRpBhApR1jJNASoVWsEvH5vf89TJw+l9Lt1ssawop0K2iYF5PmkthRdqcpYcTkFu5+f5QvFchVsNJ3TKD4cf2A== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/menu@^3.10.3": + version "3.10.3" + resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.10.3.tgz#36fe24dc3d622524388e0ea9cecdfb8e013a7365" + integrity sha512-Vd3t7fEbIOiq7kBAHaihfYf+/3Fuh0yK2KNjJ70BPtlAhMRMDVG3m0PheSTm3FFfj+uAdQdfc2YKPnMBbWjDuQ== + dependencies: + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" + +"@react-types/meter@^3.4.11": + version "3.4.11" + resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.11.tgz#dd3d59fbd90437af450d84799266817e526528b9" + integrity sha512-c4jnDWFxDp09fNpCDrq6l2RxOxcolmf/frvdtVA/d4SGvfEOoqeUakpVDuOqDD0bU58tQPG3fqT2zH8vpWiJew== + dependencies: + "@react-types/progress" "^3.5.14" + +"@react-types/numberfield@^3.8.13": + version "3.8.13" + resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.13.tgz#9939992551d4b2a08f7d1d8b71879096c2207440" + integrity sha512-zRSqInmxOTQJZt2fjAhuQK3Wa1vCOlKsRzUVvxTrE8gtQxlgFxirmobuUnjTEhwkFyb0bq8GvVfQV1E95Si2yw== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/overlays@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.9.0.tgz#c0fe30052b6795e549a0748733c84bd1d63ac9fc" + integrity sha512-T2DqMcDN5p8vb4vu2igoLrAtuewaNImLS8jsK7th7OjwQZfIWJn5Y45jSxHtXJUddEg1LkUjXYPSXCMerMcULw== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/progress@^3.5.14": + version "3.5.14" + resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.14.tgz#4ac5e15471c015105169778c5befdb1283735b8e" + integrity sha512-GeGrjOeHR/p5qQ1gGlN68jb+lL47kuddxMgdR1iEnAlYGY4OtJoEN/EM5W2ZxJRKPcJmzdcY/p/J0PXa8URbSg== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/radio@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.9.0.tgz#72e0b455e361407b2323932081da9dd692e1c1f1" + integrity sha512-phndlgqMF6/9bOOhO3le00eozNfDU1E7OHWV2cWWhGSMRFuRdf7/d+NjVtavCX75+GJ50MxvXk+KB0fjTuvKyg== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/searchfield@^3.6.4": + version "3.6.4" + resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.6.4.tgz#96962e1f788e7d1854cd630ec6ecb2cacca01a2f" + integrity sha512-gRVWnRHf7pqU0lBVlkU6XsLxvaWTPnn0EomddIBCVh0msVIyvEea8CXJppu7EpvRh+grNpiMEYeijQ+u8hixlQ== + dependencies: + "@react-types/shared" "^3.31.0" + "@react-types/textfield" "^3.12.4" + +"@react-types/select@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.10.0.tgz#19b843c532aea4e72597f77f076e656e8ca975a0" + integrity sha512-+xJwYWJoJTCGsaiPAqb6QB79ub1WKIHSmOS9lh/fPUXfUszVs05jhajaN9KjrKmnXds5uh4u6l1JH5J1l2K5pw== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/shared@^3.25.0", "@react-types/shared@^3.31.0": + version "3.31.0" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.31.0.tgz#014be53096c3728f0684550430807e9962365c15" + integrity sha512-ua5U6V66gDcbLZe4P2QeyNgPp4YWD1ymGA6j3n+s8CGExtrCPe64v+g4mvpT8Bnb985R96e4zFT61+m0YCwqMg== + +"@react-types/slider@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.8.0.tgz#89994e9d3debb001b2a99b4a0f4afd8e5c0c45e8" + integrity sha512-eN6Fd3YCPseGfvfOJDtn9Lh9CrAb8tF3cTAprEcpnGrsxmdW9JQpcuciYuLM871X5D2fYg4WaYMpZaiYssjxBQ== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/switch@^3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.13.tgz#6dbbef224874bc0f3a956c664152653ce4cec759" + integrity sha512-C2EhKBu7g7xhKboPPxhyKtROEti80Ck7TBnKclXt0D4LiwbzpR3qGfuzB+7YFItnhiauP7Uxe+bAfM5ojjtm9w== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/table@^3.13.2": + version "3.13.2" + resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.13.2.tgz#c4becb119e1ecbe35be2ec9e9d198bbeedf120bd" + integrity sha512-3/BpFIWHXTcGgQEfip87gMNCWPtPNsc3gFkW4qtsevQ+V0577KyNyvQgvFrqMZKnvz3NWFKyshBb7PTevsus4Q== + dependencies: + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" + +"@react-types/tabs@^3.3.17": + version "3.3.17" + resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.17.tgz#f6fb284077d1091a4513f56b2d35a386a9711f37" + integrity sha512-cLcdxWNJe0Kf/pKuPQbEF9Fl+axiP4gB/WVjmAdhCgQ5LCJw2dGcy1LI1SXrlS3PVclbnujD1DJ8z1lIW4Tmww== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/textfield@^3.12.4": + version "3.12.4" + resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.12.4.tgz#f95c359c5fef4cd24abf7969d3c28de77c8e1ecf" + integrity sha512-cOgzI1dT8X1JMNQ9u2UKoV2L28ROkbFEtzY9At0MqTZYYSxYp3Q7i+XRqIBehu8jOMuCtN9ed9EgwVSfkicyLQ== + dependencies: + "@react-types/shared" "^3.31.0" + +"@react-types/tooltip@^3.4.19": + version "3.4.19" + resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.19.tgz#2f30b83a0f36ad2e2d1f75531d0d6f30abb525a4" + integrity sha512-OR/pwZReWbCIxuHJYB1L4fTwliA+mzVvUJMWwXIRy6Eh5d07spS3FZEKFvOgjMxA1nyv5PLf8eyr5RuuP1GGAA== + dependencies: + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" + +"@remix-run/router@1.23.0": + version "1.23.0" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.23.0.tgz#35390d0e7779626c026b11376da6789eb8389242" + integrity sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA== + +"@rolldown/pluginutils@1.0.0-beta.27": + version "1.0.0-beta.27" + resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz#47d2bf4cef6d470b22f5831b420f8964e0bf755f" + integrity sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA== + +"@segment/analytics-core@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.8.2.tgz#f8aea312af3655e6483d0bdc160f0e05484529ab" + integrity sha512-5FDy6l8chpzUfJcNlIcyqYQq4+JTUynlVoCeCUuVz+l+6W0PXg+ljKp34R4yLVCcY5VVZohuW+HH0VLWdwYVAg== + dependencies: + "@lukeed/uuid" "^2.0.0" + "@segment/analytics-generic-utils" "1.2.0" + dset "^3.1.4" + tslib "^2.4.1" + +"@segment/analytics-generic-utils@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@segment/analytics-generic-utils/-/analytics-generic-utils-1.2.0.tgz#9232162d6dbcd18501813fdff18035ce48fd24bf" + integrity sha512-DfnW6mW3YQOLlDQQdR89k4EqfHb0g/3XvBXkovH1FstUN93eL1kfW9CsDcVQyH3bAC5ZsFyjA/o/1Q2j0QeoWw== + dependencies: + tslib "^2.4.1" + +"@segment/analytics-next@^1.70.0": + version "1.81.1" + resolved "https://registry.yarnpkg.com/@segment/analytics-next/-/analytics-next-1.81.1.tgz#1e98c44090c95c131c249aaf8ad48aa4afb964e1" + integrity sha512-nVHNhriViptjkp4004qBbvmnW9/3brjhBv2P5Cvcg7iWW41fBzUY8FbLi+8wkmSbycT9fH1pTM3TUxB6+h0Fcg== + dependencies: + "@lukeed/uuid" "^2.0.0" + "@segment/analytics-core" "1.8.2" + "@segment/analytics-generic-utils" "1.2.0" + "@segment/analytics-page-tools" "1.0.0" + "@segment/analytics.js-video-plugins" "^0.2.1" + "@segment/facade" "^3.4.9" + dset "^3.1.4" + js-cookie "3.0.1" + node-fetch "^2.6.7" + tslib "^2.4.1" + unfetch "^4.1.0" + +"@segment/analytics-page-tools@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@segment/analytics-page-tools/-/analytics-page-tools-1.0.0.tgz#f5fb9b8f0c1e80e821b0a77ca13ac53daf08a28a" + integrity sha512-o9OVB91qLB9qb0Bw1HfjmWm5AnrMNULRjx++4lBqLt8InKRX1urrRBparVlpj+yJA0sckN5ZcsfazRLuPgBYDQ== + dependencies: + tslib "^2.4.1" + +"@segment/analytics.js-video-plugins@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@segment/analytics.js-video-plugins/-/analytics.js-video-plugins-0.2.1.tgz#3596fa3887dcd9df5978dc566edf4a0aea2a9b1e" + integrity sha512-lZwCyEXT4aaHBLNK433okEKdxGAuyrVmop4BpQqQSJuRz0DglPZgd9B/XjiiWs1UyOankg2aNYMN3VcS8t4eSQ== + dependencies: + unfetch "^3.1.1" + +"@segment/facade@^3.4.9": + version "3.4.10" + resolved "https://registry.yarnpkg.com/@segment/facade/-/facade-3.4.10.tgz#118fab29cf2250d3128f9b2a16d6ec76f86e3710" + integrity sha512-xVQBbB/lNvk/u8+ey0kC/+g8pT3l0gCT8O2y9Z+StMMn3KAFAQ9w8xfgef67tJybktOKKU7pQGRPolRM1i1pdA== + dependencies: + "@segment/isodate-traverse" "^1.1.1" + inherits "^2.0.4" + new-date "^1.0.3" + obj-case "0.2.1" + +"@segment/isodate-traverse@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@segment/isodate-traverse/-/isodate-traverse-1.1.1.tgz#37e1a68b5e48a841260145f1be86d342995dfc64" + integrity sha512-+G6e1SgAUkcq0EDMi+SRLfT48TNlLPF3QnSgFGVs0V9F3o3fq/woQ2rHFlW20W0yy5NnCUH0QGU3Am2rZy/E3w== + dependencies: + "@segment/isodate" "^1.0.3" + +"@segment/isodate@1.0.3", "@segment/isodate@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@segment/isodate/-/isodate-1.0.3.tgz#f44e8202d5edd277ce822785239474b2c9411d4a" + integrity sha512-BtanDuvJqnACFkeeYje7pWULVv8RgZaqKHWwGFnL/g/TH/CcZjkIVTfGDp/MAxmilYHUkrX70SqwnYSTNEaN7A== + +"@swc/helpers@^0.5.0": + version "0.5.17" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.17.tgz#5a7be95ac0f0bf186e7e6e890e7a6f6cda6ce971" + integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A== + dependencies: + tslib "^2.8.0" + +"@tanstack/react-table@^8.20.5": + version "8.21.3" + resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.21.3.tgz#2c38c747a5731c1a07174fda764b9c2b1fb5e91b" + integrity sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww== + dependencies: + "@tanstack/table-core" "8.21.3" + +"@tanstack/table-core@8.21.3": + version "8.21.3" + resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.21.3.tgz#2977727d8fc8dfa079112d9f4d4c019110f1732c" + integrity sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg== + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + +"@types/chroma-js@2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@types/chroma-js/-/chroma-js-2.1.4.tgz#52e3a8453000cdb9ad76357c2c47dbed702d136f" + integrity sha512-l9hWzP7cp7yleJUI7P2acmpllTJNYf5uU6wh50JzSIZt3fFHe+w2FM6w9oZGBTYzjjm2qHdnQvI+fF/JF/E5jQ== + +"@types/debug@^4.0.0": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== + dependencies: + "@types/ms" "*" + +"@types/estree-jsx@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" + integrity sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg== + dependencies: + "@types/estree" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/hast@^2.0.0": + version "2.3.10" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" + integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw== + dependencies: + "@types/unist" "^2" + +"@types/hast@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" + integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ== + dependencies: + "@types/unist" "*" + +"@types/js-cookie@^2.2.6": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" + integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA== + +"@types/mdast@^4.0.0": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" + integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA== + dependencies: + "@types/unist" "*" + +"@types/ms@*": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" + integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== + +"@types/node@^22.13.10": + version "22.17.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.17.1.tgz#484a755050497ebc3b37ff5adb7470f2e3ea5f5b" + integrity sha512-y3tBaz+rjspDTylNjAX37jEC3TETEFGNJL6uQDxwF9/8GLLIjW1rvVHlynyuUKMnMr1Roq8jOv3vkopBjC4/VA== + dependencies: + undici-types "~6.21.0" + +"@types/parse-json@^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" + integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== + +"@types/prop-types@*", "@types/prop-types@^15.7.12": + version "15.7.15" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7" + integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw== + +"@types/react-dom@^18.2.7": + version "18.3.7" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.7.tgz#b89ddf2cd83b4feafcc4e2ea41afdfb95a0d194f" + integrity sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ== + +"@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.10": + version "4.4.12" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" + integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== + +"@types/react@^18.2.15": + version "18.3.23" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.23.tgz#86ae6f6b95a48c418fecdaccc8069e0fbb63696a" + integrity sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@types/unist@*", "@types/unist@^3.0.0": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" + integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== + +"@types/unist@^2", "@types/unist@^2.0.0": + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== + +"@types/uuid@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-10.0.0.tgz#e9c07fe50da0f53dc24970cca94d619ff03f6f6d" + integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== + +"@typescript-eslint/eslint-plugin@^7.0.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3" + integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/type-utils" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^6.0.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + +"@typescript-eslint/type-utils@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b" + integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== + dependencies: + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== + +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== + +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== + dependencies: + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" + +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== + dependencies: + "@typescript-eslint/types" "7.18.0" + eslint-visitor-keys "^3.4.3" + +"@uiw/color-convert@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/color-convert/-/color-convert-2.5.4.tgz#b42473cf5a70e6acb80be92daa01ce15b80e12e1" + integrity sha512-gcVsu9SfEbob9SJggmlrDhMp6bngqsEqjr7KYM86Ltq5wghmvfUnJlvVd6HxLjuGFlqy5zqbK1Z6GDLDoSmsWg== + +"@uiw/react-color-alpha@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-alpha/-/react-color-alpha-2.5.4.tgz#539a4b3fab6f57f875c0c9c67c0e42870ec987b5" + integrity sha512-TZDAsEBMlGaEa4P8nz6ZLSDa1c+XdZZ26+Hkb1rf+h2qDYSPQx8gijtiSgm+ePZGp+4+IqoG2jfXuHwAEWycmg== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-drag-event-interactive" "2.5.4" + +"@uiw/react-color-block@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-block/-/react-color-block-2.5.4.tgz#c1c36a2087fac020939ee03a5dc0e7dbf2080c91" + integrity sha512-weW/nteJNBklKrwZxLmDjxXaQ3LrkESkqh0iazzwwgY0fWh8xC/PV5TzZ2HpAMwYoB9MTRk06CsMqHSPinncMw== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-chrome@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-chrome/-/react-color-chrome-2.5.4.tgz#61295e66552a675b517de670d0aa3a35e0984ebd" + integrity sha512-jNLKCGrvkYh9UYAm/tV79gijUGFp5XlaQ3cL+Wk6gr1UIfTfwLNpr3QqZbhfdvUF8s5V1/hs64hFR6GE4PVB9Q== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-hsla" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-github" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + +"@uiw/react-color-circle@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-circle/-/react-color-circle-2.5.4.tgz#54a4bfc55a7d231f778f5abc2fbd8c5afdd1cbab" + integrity sha512-EaAZs9qsOhkFD74yx00hmd0RmCP5cKq691PZC47LDRK1o7IK05VYtcoBEL3zx8TBtUyk1A5gg1GRBRe/KxpK6w== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-colorful@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-colorful/-/react-color-colorful-2.5.4.tgz#f9692fc0ef8e441511af50364e937294e897c56f" + integrity sha512-4QQt+QjNlytdeLL4pSI2ZneN6KEMG4oPkuqTZhRwJvuS4xGonCgg542egRaBJAlszwNy/1ix82SrMAGR9sW+Bw== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + +"@uiw/react-color-compact@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-compact/-/react-color-compact-2.5.4.tgz#853ef7dd1c2d3a4029db43e1a1e9ad742d34e996" + integrity sha512-6m/qIchCvGkYzekeATgCvIodV6ORP6W//W8QSNhFnxFT+ChxLQSOpZO62QuRhQETrF9LoXNkmDrzJbIHEWy/ig== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-editable-input-hsla@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-editable-input-hsla/-/react-color-editable-input-hsla-2.5.4.tgz#3e62e611389e093209dca9d67d5603230bf18a67" + integrity sha512-9sgFpwLbGCetbKCPVYgmnh9Rn4BPoweaIzPc4CO1HXTsZSTMZahZRq8JciSzu8GXEi2V464p5igsKz264aPY0A== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + +"@uiw/react-color-editable-input-rgba@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-editable-input-rgba/-/react-color-editable-input-rgba-2.5.4.tgz#a9a1b05a8a1c34e88f7249b966d4763c6d24f383" + integrity sha512-XHkYO8JnvgzT8+7ci9VSY2GvNs2+V/HLhCZjJpXAqpU8umY2T9ryhpD0uzKdOieLg74817Ny2ESPrdT/uEGr4A== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + +"@uiw/react-color-editable-input@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-editable-input/-/react-color-editable-input-2.5.4.tgz#b1eb4bc703fd6552032ac3e98963a39b54f16721" + integrity sha512-wn++Hjgv16FCarddAj5RbR/AuGzIs+TYoCJS6wZy1X+BkWjdwN81+mHxXBq42ooge77xkj9Uhbqa7uaIYKCuJA== + +"@uiw/react-color-github@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-github/-/react-color-github-2.5.4.tgz#2920271da7c322a3bc71f37aae5d455d92dd05e3" + integrity sha512-WBTHbt8KOj/VoYybWIDRRxwuFrUtlSYFe4/sNanqezjWqeZF7ZB2fjfv0Tx9/pzqCSeRSS7X+Tm8ce49Uo+46g== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-hue@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-hue/-/react-color-hue-2.5.4.tgz#7285eafbe57deb68017f676a6baa1c943997d72a" + integrity sha512-fUbKPbChCcIkJYyLK9+FhJvvuQgCoxwokq4dma3QeDYHXMHoLqOpWrJlagF+vKqzsPd1dFcH8nPLKf0EO+UjKg== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + +"@uiw/react-color-material@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-material/-/react-color-material-2.5.4.tgz#ed1dafeb53a43db786f2ac647f10a12e22c936c8" + integrity sha512-16GrTKI7F+2gdSwmXlD13Oy4GzxgcMybAXmOrGTrmB1n6JuyUTaXW4vZrGpe3BCt9CKb7ryvLIgTaeKDECUrSQ== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + +"@uiw/react-color-name@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-name/-/react-color-name-2.5.4.tgz#5229a54f2d3a77ee5b39259636889f6937dd857a" + integrity sha512-09fHPL3IBktmoNK5wLqRJbJXMWNGJERKaU/TBKaf9CePVJnxdFsX8X/JQ/UYyMUik2lFLv7HDiuJtRJ+Mk4mcg== + dependencies: + colors-named "^1.0.1" + colors-named-hex "^1.0.1" + +"@uiw/react-color-saturation@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-saturation/-/react-color-saturation-2.5.4.tgz#69cbc69e434a27267ebfb2f0767c8990c552857a" + integrity sha512-aMiqmv91jEZfqgW44E/9S4A7t3ScvsaXcqyjX+vi2zT+H0ZmZfNKfeiytppgurAKaot12vZCZhs+Lvzi8TmXEA== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-drag-event-interactive" "2.5.4" + +"@uiw/react-color-shade-slider@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-shade-slider/-/react-color-shade-slider-2.5.4.tgz#d556b4c75b76285ba9bbb56c8fe2de1f3e971179" + integrity sha512-NeEJ/FhT2wbPNbVfuBwliKgd1BtwZIeOgHDfLOn38hAXSPUVe2LoxLcKOYH/YostsbwRqQ+vYFuNE+++49FyFA== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + +"@uiw/react-color-sketch@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-sketch/-/react-color-sketch-2.5.4.tgz#393823eac72535c0c332317dde3e69ba5bfe8d4d" + integrity sha512-A5ZcJtVPFavbeyf2EZ/V+ttfFJnfZyTzzD17rSIQEqtNaQTvmkKWiSIfiL4XsFsxG4LLyoir79eYsy5/5c2zeg== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-slider@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-slider/-/react-color-slider-2.5.4.tgz#a1efd88d0782d8014272c8e6f5cdcf5fbaf14117" + integrity sha512-OxQxlTxGuw052/MZKzGwKiIHj8a2PrYWLtUfvswZZiw4Xr1bj+dQUjSAIiz8XI4oKIVHLZU0U9XRRm+NrD7qmw== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + +"@uiw/react-color-swatch@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-swatch/-/react-color-swatch-2.5.4.tgz#e2775c91b544c0e7cc7935df99bbbce8111577c6" + integrity sha512-//eW0MuhgU0fc+v1QQ0gajY+KI/OME3e8uQ0LfcnZu2pjKVnonHJ2k8iMOno1t8vLiHU9GgYukHixqgpLTC61A== + dependencies: + "@uiw/color-convert" "2.5.4" + +"@uiw/react-color-wheel@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-wheel/-/react-color-wheel-2.5.4.tgz#cbdcc29b9ee904407aa8bc5453f7280ef7c084e3" + integrity sha512-EQ9mBsBkhiCiHaEUagiF6wGIQuoyFc88HU4x4Kk/sQ+VBUxGpxVxMXRvuBeUwLgypbXSbjClSmQs1mtrJ3e1BQ== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-drag-event-interactive" "2.5.4" + +"@uiw/react-color@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color/-/react-color-2.5.4.tgz#c088344b2313f98a8a265f19e4ea49e6fe3cdac2" + integrity sha512-hRRqXH4ppqoJdHjlf4dBrHcvQ3GLlmCYDd8KPX9yugxKVSUB8CSNFItF2tfUc4WvdwIC43euqN6bznecWWjKBA== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-block" "2.5.4" + "@uiw/react-color-chrome" "2.5.4" + "@uiw/react-color-circle" "2.5.4" + "@uiw/react-color-colorful" "2.5.4" + "@uiw/react-color-compact" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-hsla" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-github" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-material" "2.5.4" + "@uiw/react-color-name" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + "@uiw/react-color-shade-slider" "2.5.4" + "@uiw/react-color-sketch" "2.5.4" + "@uiw/react-color-slider" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + "@uiw/react-color-wheel" "2.5.4" + +"@uiw/react-drag-event-interactive@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-drag-event-interactive/-/react-drag-event-interactive-2.5.4.tgz#743a43695f8e98bdaaa05a3b26204274a24aa0d6" + integrity sha512-VEzRKVPp5tuMDntxVsIJ8liJgJ4t3ZIGORHWReAGzt2IBIFxEAxtN7YsDuoxN2G96qBoWgwZptmAUKdUPHhPMQ== + +"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + +"@vitejs/plugin-react@^4.5.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz#647af4e7bb75ad3add578e762ad984b90f4a24b9" + integrity sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA== + dependencies: + "@babel/core" "^7.28.0" + "@babel/plugin-transform-react-jsx-self" "^7.27.1" + "@babel/plugin-transform-react-jsx-source" "^7.27.1" + "@rolldown/pluginutils" "1.0.0-beta.27" + "@types/babel__core" "^7.20.5" + react-refresh "^0.17.0" + +"@xobotyi/scrollbar-width@^1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" + integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.9.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +attr-accept@^2.2.2: + version "2.2.5" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.5.tgz#d7061d958e6d4f97bf8665c68b75851a0713ab5e" + integrity sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ== + +autoprefixer@^10.4.21: + version "10.4.21" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.21.tgz#77189468e7a8ad1d9a37fbc08efc9f480cf0a95d" + integrity sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ== + dependencies: + browserslist "^4.24.4" + caniuse-lite "^1.0.30001702" + fraction.js "^4.3.7" + normalize-range "^0.1.2" + picocolors "^1.1.1" + postcss-value-parser "^4.2.0" + +axios@^1.8.4: + version "1.11.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.11.0.tgz#c2ec219e35e414c025b2095e8b8280278478fdb6" + integrity sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.4" + proxy-from-env "^1.1.0" + +babel-plugin-macros@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-arraybuffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== + +bin-pack@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bin-pack/-/bin-pack-1.0.2.tgz#c2a014edbf0bed70a3292062ed46577b96120679" + integrity sha512-aOk0SxEon5LF9cMxQFViSKb4qccG6rs7XKyMXIb1J8f8LA2acTIWnHdT0IOTe4gYBbqgjdbuTZ5f+UP+vlh4Mw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0, browserslist@^4.24.4: + version "4.25.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.2.tgz#90c1507143742d743544ae6e92bca3348adff667" + integrity sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA== + dependencies: + caniuse-lite "^1.0.30001733" + electron-to-chromium "^1.5.199" + node-releases "^2.0.19" + update-browserslist-db "^1.1.3" + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001733: + version "1.0.30001733" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001733.tgz#918405ed6647a62840fb328832cf5a03f986974b" + integrity sha512-e4QKw/O2Kavj2VQTKZWrwzkt3IxOmIlU6ajRb6LP64LHpBo1J67k2Hi4Vu/TgJWsNtynurfS0uK3MaUTCPfu5Q== + +ccount@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" + integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-entities-html4@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" + integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities-legacy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" + integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-entities@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" + integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + +character-reference-invalid@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" + integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== + +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chroma-js@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-2.4.2.tgz#dffc214ed0c11fa8eefca2c36651d8e57cbfb2b0" + integrity sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A== + +classnames@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== + +clsx@^2.0.0, clsx@^2.1.0, clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +colors-named-hex@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/colors-named-hex/-/colors-named-hex-1.0.2.tgz#353165cc548ef0fbd770280bf441ec2dfc1bb386" + integrity sha512-k6kq1e1pUCQvSVwIaGFq2l0LrkAPQZWyeuZn1Z8nOiYSEZiKoFj4qx690h2Kd34DFl9Me0gKS6MUwAMBJj8nuA== + +colors-named@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/colors-named/-/colors-named-1.0.2.tgz#362dd6b520c08da8d9a77250174f0d5f2cfc5b81" + integrity sha512-2ANq2r393PV9njYUD66UdfBcxR1slMqRA3QRTWgCx49JoCJ+kOhyfbQYxKJbPZQIhZUcNjVOs5AlyY1WwXec3w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + +comma-separated-tokens@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" + integrity sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concaveman@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/concaveman/-/concaveman-1.2.1.tgz#47d20b4521125c15fabf453653c2696d9ee41e0b" + integrity sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw== + dependencies: + point-in-polygon "^1.1.0" + rbush "^3.0.1" + robust-predicates "^2.0.4" + tinyqueue "^2.0.3" + +convert-source-map@^1.5.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +copy-to-clipboard@^3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" + integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== + dependencies: + toggle-selection "^1.0.6" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cose-base@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a" + integrity sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg== + dependencies: + layout-base "^1.0.0" + +cosmiconfig@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-spawn@^7.0.2, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-in-js-utils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz#640ae6a33646d401fc720c54fc61c42cd76ae2bb" + integrity sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A== + dependencies: + hyphenate-style-name "^1.0.3" + +css-line-break@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0" + integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w== + dependencies: + utrie "^1.0.2" + +css-tree@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^3.0.2, csstype@^3.1.2, csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +cytoscape-cose-bilkent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b" + integrity sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ== + dependencies: + cose-base "^1.0.0" + +cytoscape@^3.23.0: + version "3.33.0" + resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.33.0.tgz#c08136096f568d0f9b438406ec722f1a093b4e16" + integrity sha512-2d2EwwhaxLWC8ahkH1PpQwCyu6EY3xDRdcEJXrLTb4fOUtVc+YWQalHU67rFS1a6ngj1fgv9dQLtJxP/KAFZEw== + +"d3-dispatch@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +d3-force@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" + integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== + dependencies: + d3-dispatch "1 - 3" + d3-quadtree "1 - 3" + d3-timer "1 - 3" + +"d3-quadtree@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" + integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== + +"d3-timer@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +date-fns@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14" + integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg== + +date-fns@^3.3.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" + integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== + +debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +decimal.js@^10.4.3: + version "10.6.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + +decode-named-character-reference@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz#25c32ae6dd5e21889549d40f676030e9514cc0ed" + integrity sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q== + dependencies: + character-entities "^2.0.0" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dequal@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +detect-browser@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" + integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== + +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + +devlop@^1.0.0, devlop@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" + integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== + dependencies: + dequal "^2.0.0" + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +dset@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248" + integrity sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.5.199: + version "1.5.199" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.199.tgz#4d8be9c78362c05f095eb7392e9a54f1fb14fd3a" + integrity sha512-3gl0S7zQd88kCAZRO/DnxtBKuhMO4h0EaQIN3YgZfV6+pW+5+bf2AdQeHNESCoaQqo/gjGVYEf2YM4O5HJQqpQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +entities@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694" + integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error-stack-parser@^2.0.6: + version "2.1.4" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" + integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== + dependencies: + stackframe "^1.3.4" + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +esbuild@^0.18.10: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + +eslint-config-prettier@^10.1.1: + version "10.1.8" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97" + integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== + +eslint-plugin-react-hooks@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3" + integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg== + +eslint-plugin-react-refresh@^0.4.20: + version "0.4.20" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz#3bbfb5c8637e28d19ce3443686445e502ecd18ba" + integrity sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA== + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.45.0: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-util-is-identifier-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd" + integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +eyedropper-polyfill@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/eyedropper-polyfill/-/eyedropper-polyfill-1.0.2.tgz#8e6d6e1a872c292e1ea4c474c97b83256447309c" + integrity sha512-tQWOOIxjQpn79Jd03gHyqd8HwDof03LGDiYzwHfLI345/L9XUb5ze3vC0RMYoQhuoslgP5evs1tYN5cl7fwiHw== + dependencies: + html2canvas "^1.4.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9, fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-shallow-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" + integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== + +fastest-stable-stringify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76" + integrity sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q== + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fault@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-selector@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc" + integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw== + dependencies: + tslib "^2.4.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +focus-lock@^1.3.5: + version "1.3.6" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-1.3.6.tgz#955eec1e10591d56f679258edb94aedb11d691cd" + integrity sha512-Ik/6OCk9RQQ0T5Xw+hKNLWrjSMtv51dD4GRmJjbD5a58TIEpI5a5iXagKVl3Z5UuyslMCA8Xwnu76jQob62Yhg== + dependencies: + tslib "^2.0.3" + +follow-redirects@^1.15.6: + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== + +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + +form-data@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + +format@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" + integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== + +fraction.js@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +gl-matrix@^3.3.0: + version "3.4.4" + resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.4.4.tgz#7789ee4982f62c7a7af447ee488f3bd6b0c77003" + integrity sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + 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" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +glsl-inject-defines@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz#dd1aacc2c17fcb2bd3fc32411c6633d0d7b60fd4" + integrity sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A== + dependencies: + glsl-token-inject-block "^1.0.0" + glsl-token-string "^1.0.1" + glsl-tokenizer "^2.0.2" + +glsl-token-inject-block@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz#e1015f5980c1091824adaa2625f1dfde8bd00034" + integrity sha512-q/m+ukdUBuHCOtLhSr0uFb/qYQr4/oKrPSdIK2C4TD+qLaJvqM9wfXIF/OOBjuSA3pUoYHurVRNao6LTVVUPWA== + +glsl-token-string@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/glsl-token-string/-/glsl-token-string-1.0.1.tgz#59441d2f857de7c3449c945666021ece358e48ec" + integrity sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg== + +glsl-tokenizer@^2.0.2: + version "2.1.5" + resolved "https://registry.yarnpkg.com/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz#1c2e78c16589933c274ba278d0a63b370c5fee1a" + integrity sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA== + dependencies: + through2 "^0.6.3" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +graphlib@2.1.8, graphlib@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" + integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A== + dependencies: + lodash "^4.17.15" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hast-util-from-parse5@^8.0.0: + version "8.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz#830a35022fff28c3fea3697a98c2f4cc6b835a2e" + integrity sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + hastscript "^9.0.0" + property-information "^7.0.0" + vfile "^6.0.0" + vfile-location "^5.0.0" + web-namespaces "^2.0.0" + +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + +hast-util-parse-selector@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27" + integrity sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A== + dependencies: + "@types/hast" "^3.0.0" + +hast-util-raw@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-9.1.0.tgz#79b66b26f6f68fb50dfb4716b2cdca90d92adf2e" + integrity sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + "@ungap/structured-clone" "^1.0.0" + hast-util-from-parse5 "^8.0.0" + hast-util-to-parse5 "^8.0.0" + html-void-elements "^3.0.0" + mdast-util-to-hast "^13.0.0" + parse5 "^7.0.0" + unist-util-position "^5.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + web-namespaces "^2.0.0" + zwitch "^2.0.0" + +hast-util-to-jsx-runtime@^2.0.0: + version "2.3.6" + resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz#ff31897aae59f62232e21594eac7ef6b63333e98" + integrity sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg== + dependencies: + "@types/estree" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + comma-separated-tokens "^2.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + hast-util-whitespace "^3.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + style-to-js "^1.0.0" + unist-util-position "^5.0.0" + vfile-message "^4.0.0" + +hast-util-to-parse5@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz#477cd42d278d4f036bc2ea58586130f6f39ee6ed" + integrity sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw== + dependencies: + "@types/hast" "^3.0.0" + comma-separated-tokens "^2.0.0" + devlop "^1.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + web-namespaces "^2.0.0" + zwitch "^2.0.0" + +hast-util-whitespace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz#7778ed9d3c92dd9e8c5c8f648a49c21fc51cb621" + integrity sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw== + dependencies: + "@types/hast" "^3.0.0" + +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +hastscript@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-9.0.1.tgz#dbc84bef6051d40084342c229c451cd9dc567dff" + integrity sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w== + dependencies: + "@types/hast" "^3.0.0" + comma-separated-tokens "^2.0.0" + hast-util-parse-selector "^4.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + +highlight.js@^10.4.1, highlight.js@~10.7.0: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +html-url-attributes@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.1.tgz#83b052cd5e437071b756cd74ae70f708870c2d87" + integrity sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ== + +html-void-elements@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-3.0.0.tgz#fc9dbd84af9e747249034d4d62602def6517f1d7" + integrity sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg== + +html2canvas@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543" + integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA== + dependencies: + css-line-break "^2.1.0" + text-segmentation "^1.0.3" + +hyphenate-style-name@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz#1797bf50369588b47b72ca6d5e65374607cf4436" + integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw== + +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.4, inherits@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inline-style-parser@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.4.tgz#f4af5fe72e612839fcd453d989a586566d695f22" + integrity sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q== + +inline-style-prefixer@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz#9310f3cfa2c6f3901d1480f373981c02691781e8" + integrity sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw== + dependencies: + css-in-js-utils "^3.1.0" + +intl-messageformat@^10.1.0: + version "10.7.16" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.16.tgz#d909f9f9f4ab857fbe681d559b958dd4dd9f665a" + integrity sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug== + dependencies: + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/icu-messageformat-parser" "2.11.2" + tslib "^2.8.0" + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-hexadecimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" + integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jiti@^1.21.6: + version "1.21.7" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.7.tgz#9dd81043424a3d28458b193d965f0d18a2300ba9" + integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A== + +js-cookie@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414" + integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw== + +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +layout-base@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-1.0.2.tgz#1291e296883c322a9dd4c5dd82063721b53e26e2" + integrity sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@^3.0.0, lilconfig@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@4.17.21, lodash@^4.17.15, lodash@^4.17.19: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loglevel@^1.8.0: + version "1.9.2" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" + integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== + +longest-streak@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" + integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== + +loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lowlight@^1.17.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" + integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw== + dependencies: + fault "^1.0.0" + highlight.js "~10.7.0" + +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +markdown-table@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.4.tgz#fe44d6d410ff9d6f2ea1797a3f60aa4d2b631c2a" + integrity sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +mdast-util-find-and-replace@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz#70a3174c894e14df722abf43bc250cbae44b11df" + integrity sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg== + dependencies: + "@types/mdast" "^4.0.0" + escape-string-regexp "^5.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + +mdast-util-from-markdown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz#4850390ca7cf17413a9b9a0fbefcd1bc0eb4160a" + integrity sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + mdast-util-to-string "^4.0.0" + micromark "^4.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-decode-string "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-stringify-position "^4.0.0" + +mdast-util-gfm-autolink-literal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz#abd557630337bd30a6d5a4bd8252e1c2dc0875d5" + integrity sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ== + dependencies: + "@types/mdast" "^4.0.0" + ccount "^2.0.0" + devlop "^1.0.0" + mdast-util-find-and-replace "^3.0.0" + micromark-util-character "^2.0.0" + +mdast-util-gfm-footnote@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz#7778e9d9ca3df7238cc2bd3fa2b1bf6a65b19403" + integrity sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + +mdast-util-gfm-strikethrough@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz#d44ef9e8ed283ac8c1165ab0d0dfd058c2764c16" + integrity sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-gfm-table@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz#7a435fb6223a72b0862b33afbd712b6dae878d38" + integrity sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + markdown-table "^3.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-gfm-task-list-item@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz#e68095d2f8a4303ef24094ab642e1047b991a936" + integrity sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ== + dependencies: + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-gfm@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz#2cdf63b92c2a331406b0fb0db4c077c1b0331751" + integrity sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ== + dependencies: + mdast-util-from-markdown "^2.0.0" + mdast-util-gfm-autolink-literal "^2.0.0" + mdast-util-gfm-footnote "^2.0.0" + mdast-util-gfm-strikethrough "^2.0.0" + mdast-util-gfm-table "^2.0.0" + mdast-util-gfm-task-list-item "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdx-expression@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz#43f0abac9adc756e2086f63822a38c8d3c3a5096" + integrity sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-mdx-jsx@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz#fd04c67a2a7499efb905a8a5c578dddc9fdada0d" + integrity sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + ccount "^2.0.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" + +mdast-util-mdxjs-esm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz#019cfbe757ad62dd557db35a695e7314bcc9fa97" + integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== + dependencies: + "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + +mdast-util-phrasing@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz#7cc0a8dec30eaf04b7b1a9661a92adb3382aa6e3" + integrity sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w== + dependencies: + "@types/mdast" "^4.0.0" + unist-util-is "^6.0.0" + +mdast-util-to-hast@^13.0.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz#5ca58e5b921cc0a3ded1bc02eed79a4fe4fe41f4" + integrity sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@ungap/structured-clone" "^1.0.0" + devlop "^1.0.0" + micromark-util-sanitize-uri "^2.0.0" + trim-lines "^3.0.0" + unist-util-position "^5.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + +mdast-util-to-markdown@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz#f910ffe60897f04bb4b7e7ee434486f76288361b" + integrity sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-decode-string "^2.0.0" + unist-util-visit "^5.0.0" + zwitch "^2.0.0" + +mdast-util-to-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" + integrity sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== + dependencies: + "@types/mdast" "^4.0.0" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromark-core-commonmark@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz#c691630e485021a68cf28dbc2b2ca27ebf678cd4" + integrity sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg== + dependencies: + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-factory-destination "^2.0.0" + micromark-factory-label "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-factory-title "^2.0.0" + micromark-factory-whitespace "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-html-tag-name "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-autolink-literal@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz#6286aee9686c4462c1e3552a9d505feddceeb935" + integrity sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-footnote@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz#4dab56d4e398b9853f6fe4efac4fc9361f3e0750" + integrity sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw== + dependencies: + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-strikethrough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz#86106df8b3a692b5f6a92280d3879be6be46d923" + integrity sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-table@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz#fac70bcbf51fe65f5f44033118d39be8a9b5940b" + integrity sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg== + dependencies: + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm-tagfilter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz#f26d8a7807b5985fba13cf61465b58ca5ff7dc57" + integrity sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg== + dependencies: + micromark-util-types "^2.0.0" + +micromark-extension-gfm-task-list-item@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz#bcc34d805639829990ec175c3eea12bb5b781f2c" + integrity sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw== + dependencies: + devlop "^1.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-gfm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz#3e13376ab95dd7a5cfd0e29560dfe999657b3c5b" + integrity sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w== + dependencies: + micromark-extension-gfm-autolink-literal "^2.0.0" + micromark-extension-gfm-footnote "^2.0.0" + micromark-extension-gfm-strikethrough "^2.0.0" + micromark-extension-gfm-table "^2.0.0" + micromark-extension-gfm-tagfilter "^2.0.0" + micromark-extension-gfm-task-list-item "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-destination@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz#8fef8e0f7081f0474fbdd92deb50c990a0264639" + integrity sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-label@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz#5267efa97f1e5254efc7f20b459a38cb21058ba1" + integrity sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg== + dependencies: + devlop "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-space@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz#36d0212e962b2b3121f8525fc7a3c7c029f334fc" + integrity sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-title@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz#237e4aa5d58a95863f01032d9ee9b090f1de6e94" + integrity sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-whitespace@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz#06b26b2983c4d27bfcc657b33e25134d4868b0b1" + integrity sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-character@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz#2f987831a40d4c510ac261e89852c4e9703ccda6" + integrity sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-chunked@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz#47fbcd93471a3fccab86cff03847fc3552db1051" + integrity sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-classify-character@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz#d399faf9c45ca14c8b4be98b1ea481bced87b629" + integrity sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-combine-extensions@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz#2a0f490ab08bff5cc2fd5eec6dd0ca04f89b30a9" + integrity sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg== + dependencies: + micromark-util-chunked "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-decode-numeric-character-reference@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz#fcf15b660979388e6f118cdb6bf7d79d73d26fe5" + integrity sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-decode-string@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz#6cb99582e5d271e84efca8e61a807994d7161eb2" + integrity sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-symbol "^2.0.0" + +micromark-util-encode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz#0d51d1c095551cfaac368326963cf55f15f540b8" + integrity sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw== + +micromark-util-html-tag-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz#e40403096481986b41c106627f98f72d4d10b825" + integrity sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA== + +micromark-util-normalize-identifier@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz#c30d77b2e832acf6526f8bf1aa47bc9c9438c16d" + integrity sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q== + dependencies: + micromark-util-symbol "^2.0.0" + +micromark-util-resolve-all@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz#e1a2d62cdd237230a2ae11839027b19381e31e8b" + integrity sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg== + dependencies: + micromark-util-types "^2.0.0" + +micromark-util-sanitize-uri@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz#ab89789b818a58752b73d6b55238621b7faa8fd7" + integrity sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-symbol "^2.0.0" + +micromark-util-subtokenize@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz#d8ade5ba0f3197a1cf6a2999fbbfe6357a1a19ee" + integrity sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-symbol@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz#e5da494e8eb2b071a0d08fb34f6cefec6c0a19b8" + integrity sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q== + +micromark-util-types@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.2.tgz#f00225f5f5a0ebc3254f96c36b6605c4b393908e" + integrity sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA== + +micromark@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.2.tgz#91395a3e1884a198e62116e33c9c568e39936fdb" + integrity sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +mobx@^3.2.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-3.6.2.tgz#fb9f5ff5090539a1ad54e75dc4c098b602693320" + integrity sha512-Dq3boJFLpZEvuh5a/MbHLUIyN9XobKWIb0dBfkNOJffNkE3vtuY0C9kSDVpfH8BB0BPkVw8g22qCv7d05LEhKg== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nano-css@^5.6.2: + version "5.6.2" + resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.6.2.tgz#584884ddd7547278f6d6915b6805069742679a32" + integrity sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + css-tree "^1.1.2" + csstype "^3.1.2" + fastest-stable-stringify "^2.0.2" + inline-style-prefixer "^7.0.1" + rtl-css-js "^1.16.1" + stacktrace-js "^2.0.2" + stylis "^4.3.0" + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +new-date@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/new-date/-/new-date-1.0.3.tgz#a5956086d3f5ed43d0b210d87a10219ccb7a2326" + integrity sha512-0fsVvQPbo2I18DT2zVHpezmeeNYV2JaJSrseiHLc17GNOxJzUdx5mvSigPu8LtIfZSij5i1wXnXFspEs2CD6hA== + dependencies: + "@segment/isodate" "1.0.3" + +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-pid-controller@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/node-pid-controller/-/node-pid-controller-1.0.1.tgz#779d1a19c4a3a54284ed0d50da83bf4125f2abf5" + integrity sha512-36gdeRz2emhIsznLpXksJSqmR13NU3vR+rkRlfHWCGGlZu9fK+dcTPRpud0FiH6b2Nhwm0kbcVk7vXFlg8Sw1w== + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +obj-case@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/obj-case/-/obj-case-0.2.1.tgz#13a554d04e5ca32dfd9d566451fd2b0e11007f1a" + integrity sha512-PquYBBTy+Y6Ob/O2574XHhDtHJlV1cJHMCgW+rDRc9J5hhmRelJB3k5dTK/3cVmFVtzvAKuENeuLpoyTzMzkOg== + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-entities@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.2.tgz#61d46f5ed28e4ee62e9ddc43d6b010188443f159" + integrity sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw== + dependencies: + "@types/unist" "^2.0.0" + character-entities-legacy "^3.0.0" + character-reference-invalid "^2.0.0" + decode-named-character-reference "^1.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + is-hexadecimal "^2.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@^7.0.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05" + integrity sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw== + dependencies: + entities "^6.0.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pirates@^4.0.1: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +point-in-polygon@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/point-in-polygon/-/point-in-polygon-1.1.0.tgz#b0af2616c01bdee341cbf2894df643387ca03357" + integrity sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw== + +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-js@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== + dependencies: + camelcase-css "^2.0.1" + +postcss-load-config@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== + dependencies: + lilconfig "^3.0.0" + yaml "^2.3.4" + +postcss-nested@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131" + integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== + dependencies: + postcss-selector-parser "^6.1.1" + +postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.4.27, postcss@^8.4.47, postcss@^8.5.6: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@^3.5.3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== + +prismjs@^1.27.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9" + integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== + +prismjs@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" + integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== + +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + +property-information@^6.0.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.5.0.tgz#6212fbb52ba757e92ef4fb9d657563b933b7ffec" + integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== + +property-information@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-7.1.0.tgz#b622e8646e02b580205415586b40804d3e8bfd5d" + integrity sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quickselect@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018" + integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw== + +rbush@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf" + integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w== + dependencies: + quickselect "^2.0.0" + +re-resizable@6.11.2: + version "6.11.2" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.11.2.tgz#2e8f7119ca3881d5b5aea0ffa014a80e5c1252b3" + integrity sha512-2xI2P3OHs5qw7K0Ud1aLILK6MQxW50TcO+DetD9eIV58j84TqYeHoZcL9H4GXFXXIh7afhH8mv5iUCXII7OW7A== + +react-aria@3.35.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.35.0.tgz#205e3bf253b0540d7428590b7aed991a1593fc9a" + integrity sha512-cbbd3iIveLDRnpVrpc1iuz8OMlDdH6u8EjncW3MQuYOiEGaho9xcDtWMKiSEIZASEnd7LK4Rgm5iVPr2O+cssw== + dependencies: + "@internationalized/string" "^3.2.4" + "@react-aria/breadcrumbs" "^3.5.17" + "@react-aria/button" "^3.10.0" + "@react-aria/calendar" "^3.5.12" + "@react-aria/checkbox" "^3.14.7" + "@react-aria/color" "^3.0.0" + "@react-aria/combobox" "^3.10.4" + "@react-aria/datepicker" "^3.11.3" + "@react-aria/dialog" "^3.5.18" + "@react-aria/dnd" "^3.7.3" + "@react-aria/focus" "^3.18.3" + "@react-aria/gridlist" "^3.9.4" + "@react-aria/i18n" "^3.12.3" + "@react-aria/interactions" "^3.22.3" + "@react-aria/label" "^3.7.12" + "@react-aria/link" "^3.7.5" + "@react-aria/listbox" "^3.13.4" + "@react-aria/menu" "^3.15.4" + "@react-aria/meter" "^3.4.17" + "@react-aria/numberfield" "^3.11.7" + "@react-aria/overlays" "^3.23.3" + "@react-aria/progress" "^3.4.17" + "@react-aria/radio" "^3.10.8" + "@react-aria/searchfield" "^3.7.9" + "@react-aria/select" "^3.14.10" + "@react-aria/selection" "^3.20.0" + "@react-aria/separator" "^3.4.3" + "@react-aria/slider" "^3.7.12" + "@react-aria/ssr" "^3.9.6" + "@react-aria/switch" "^3.6.8" + "@react-aria/table" "^3.15.4" + "@react-aria/tabs" "^3.9.6" + "@react-aria/tag" "^3.4.6" + "@react-aria/textfield" "^3.14.9" + "@react-aria/tooltip" "^3.7.8" + "@react-aria/utils" "^3.25.3" + "@react-aria/visually-hidden" "^3.8.16" + "@react-types/shared" "^3.25.0" + +react-clientside-effect@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.8.tgz#0b90a9d7b2a1823a3a10ed1ea3f651f7e0301cb7" + integrity sha512-ma2FePH0z3px2+WOu6h+YycZcEvFmmxIlAb62cF52bG86eMySciO/EQZeQMXd07kPCYB0a1dWDT5J+KE9mCDUw== + dependencies: + "@babel/runtime" "^7.12.13" + +react-datepicker@6.9.0: + version "6.9.0" + resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-6.9.0.tgz#0ad234dad81d567ae64cad79697bbad69c95490b" + integrity sha512-QTxuzeem7BUfVFWv+g5WuvzT0c5BPo+XTCNbMTZKSZQLU+cMMwSUHwspaxuIcDlwNcOH0tiJ+bh1fJ2yxOGYWA== + dependencies: + "@floating-ui/react" "^0.26.2" + clsx "^2.1.0" + date-fns "^3.3.1" + prop-types "^15.7.2" + react-onclickoutside "^6.13.0" + +react-dom@^18.2.0, react-dom@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react-dropzone@14.2.9: + version "14.2.9" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.2.9.tgz#193a33f9035e29fc91abf24e50de5d66cfa7c8c0" + integrity sha512-jRZsMC7h48WONsOLHcmhyn3cRWJoIPQjPApvt/sJVfnYaB3Qltn025AoRTTJaj4WdmmgmLl6tUQg1s0wOhpodQ== + dependencies: + attr-accept "^2.2.2" + file-selector "^0.6.0" + prop-types "^15.8.1" + +react-focus-lock@2.13.2: + version "2.13.2" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.13.2.tgz#e1addac2f8b9550bc0581f3c416755ba0f81f5ef" + integrity sha512-T/7bsofxYqnod2xadvuwjGKHOoL5GH7/EIPI5UyEvaU/c2CcphvGI371opFtuY/SYdbMsNiuF4HsHQ50nA/TKQ== + dependencies: + "@babel/runtime" "^7.0.0" + focus-lock "^1.3.5" + prop-types "^15.6.2" + react-clientside-effect "^1.2.6" + use-callback-ref "^1.3.2" + use-sidecar "^1.1.2" + +react-icons@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.5.0.tgz#8aa25d3543ff84231685d3331164c00299cdfaf2" + integrity sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw== + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^19.0.0: + version "19.1.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.1.1.tgz#038ebe313cf18e1fd1235d51c87360eb87f7c36a" + integrity sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA== + +react-markdown@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-10.1.0.tgz#e22bc20faddbc07605c15284255653c0f3bad5ca" + integrity sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + hast-util-to-jsx-runtime "^2.0.0" + html-url-attributes "^3.0.0" + mdast-util-to-hast "^13.0.0" + remark-parse "^11.0.0" + remark-rehype "^11.0.0" + unified "^11.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + +react-onclickoutside@^6.13.0: + version "6.13.2" + resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.2.tgz#caa6df2c0cfe017506548fa810303fb85d13fb7c" + integrity sha512-h6Hbf1c8b7tIYY4u90mDdBLY4+AGQVMFtIE89HgC0DtVCh/JfKl477gYqUtGLmjZBKK3MJxomP/lFiLbz4sq9A== + +react-refresh@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.17.0.tgz#b7e579c3657f23d04eccbe4ad2e58a8ed51e7e53" + integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ== + +react-router-dom@^6.23.1: + version "6.30.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.30.1.tgz#da2580c272ddb61325e435478566be9563a4a237" + integrity sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw== + dependencies: + "@remix-run/router" "1.23.0" + react-router "6.30.1" + +react-router@6.30.1, react-router@^6.23.1: + version "6.30.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.30.1.tgz#ecb3b883c9ba6dbf5d319ddbc996747f4ab9f4c3" + integrity sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ== + dependencies: + "@remix-run/router" "1.23.0" + +react-select@5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.9.0.tgz#41325b7bfe8452a8d401b82fc4fb7d44a03e29c5" + integrity sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw== + dependencies: + "@babel/runtime" "^7.12.0" + "@emotion/cache" "^11.4.0" + "@emotion/react" "^11.8.1" + "@floating-ui/dom" "^1.0.1" + "@types/react-transition-group" "^4.4.0" + memoize-one "^6.0.0" + prop-types "^15.6.0" + react-transition-group "^4.3.0" + use-isomorphic-layout-effect "^1.2.0" + +react-stately@3.33.0: + version "3.33.0" + resolved "https://registry.yarnpkg.com/react-stately/-/react-stately-3.33.0.tgz#51bf4f7e99b177d491a8260981b987f9e98e39f2" + integrity sha512-DNPOxYAPuhuXwSuE1s1K7iSgqG2QOBUZq3bsLAd4gUUZje6Qepkhe7TzK2LWarQYAZ3gC9Xhmnz8ie1fdCo0GA== + dependencies: + "@react-stately/calendar" "^3.5.5" + "@react-stately/checkbox" "^3.6.9" + "@react-stately/collections" "^3.11.0" + "@react-stately/color" "^3.8.0" + "@react-stately/combobox" "^3.10.0" + "@react-stately/data" "^3.11.7" + "@react-stately/datepicker" "^3.10.3" + "@react-stately/dnd" "^3.4.3" + "@react-stately/form" "^3.0.6" + "@react-stately/list" "^3.11.0" + "@react-stately/menu" "^3.8.3" + "@react-stately/numberfield" "^3.9.7" + "@react-stately/overlays" "^3.6.11" + "@react-stately/radio" "^3.10.8" + "@react-stately/searchfield" "^3.5.7" + "@react-stately/select" "^3.6.8" + "@react-stately/selection" "^3.17.0" + "@react-stately/slider" "^3.5.8" + "@react-stately/table" "^3.12.3" + "@react-stately/tabs" "^3.6.10" + "@react-stately/toggle" "^3.7.8" + "@react-stately/tooltip" "^3.4.13" + "@react-stately/tree" "^3.8.5" + "@react-types/shared" "^3.25.0" + +react-syntax-highlighter@15.5.0: + version "15.5.0" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz#4b3eccc2325fa2ec8eff1e2d6c18fa4a9e07ab20" + integrity sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg== + dependencies: + "@babel/runtime" "^7.3.1" + highlight.js "^10.4.1" + lowlight "^1.17.0" + prismjs "^1.27.0" + refractor "^3.6.0" + +react-transition-group@^4.3.0, react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react-universal-interface@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" + integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== + +react-use@17.5.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.5.1.tgz#19fc2ae079775d8450339e9fa8dbe25b17f2263c" + integrity sha512-LG/uPEVRflLWMwi3j/sZqR00nF6JGqTTDblkXK2nzXsIvij06hXl1V/MZIlwj1OKIQUtlh1l9jK8gLsRyCQxMg== + dependencies: + "@types/js-cookie" "^2.2.6" + "@xobotyi/scrollbar-width" "^1.9.5" + copy-to-clipboard "^3.3.1" + fast-deep-equal "^3.1.3" + fast-shallow-equal "^1.0.0" + js-cookie "^2.2.1" + nano-css "^5.6.2" + react-universal-interface "^0.6.2" + resize-observer-polyfill "^1.5.1" + screenfull "^5.1.0" + set-harmonic-interval "^1.0.1" + throttle-debounce "^3.0.1" + ts-easing "^0.2.0" + tslib "^2.1.0" + +react@^18.2.0, react@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== + dependencies: + pify "^2.3.0" + +"readable-stream@>=1.0.33-1 <1.1.0-0": + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +refractor@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" + integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA== + dependencies: + hastscript "^6.0.0" + parse-entities "^2.0.0" + prismjs "~1.27.0" + +rehype-raw@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-7.0.0.tgz#59d7348fd5dbef3807bbaa1d443efd2dd85ecee4" + integrity sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww== + dependencies: + "@types/hast" "^3.0.0" + hast-util-raw "^9.0.0" + vfile "^6.0.0" + +remark-gfm@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-4.0.1.tgz#33227b2a74397670d357bf05c098eaf8513f0d6b" + integrity sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-gfm "^3.0.0" + micromark-extension-gfm "^3.0.0" + remark-parse "^11.0.0" + remark-stringify "^11.0.0" + unified "^11.0.0" + +remark-parse@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" + integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + micromark-util-types "^2.0.0" + unified "^11.0.0" + +remark-rehype@^11.0.0: + version "11.1.2" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.2.tgz#2addaadda80ca9bd9aa0da763e74d16327683b37" + integrity sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-hast "^13.0.0" + unified "^11.0.0" + vfile "^6.0.0" + +remark-stringify@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-11.0.0.tgz#4c5b01dd711c269df1aaae11743eb7e2e7636fd3" + integrity sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw== + dependencies: + "@types/mdast" "^4.0.0" + mdast-util-to-markdown "^2.0.0" + unified "^11.0.0" + +resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + +resizelistener@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resizelistener/-/resizelistener-1.1.0.tgz#17ae50ce66f725b60c7297573a29926796867e87" + integrity sha512-PFRj7BEEXpTBi/QJr1dO9NBgRFg83W5JHzCAVkqJ/XlaDBPqBNZKR5lCKqLxIuObbykvdfYcLrQESwaV4qwL9w== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.1.7, resolve@^1.19.0, resolve@^1.22.8: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +robust-predicates@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-2.0.4.tgz#0a2367a93abd99676d075981707f29cfb402248b" + integrity sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg== + +rollup@^3.27.1: + version "3.29.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" + integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== + optionalDependencies: + fsevents "~2.3.2" + +rtl-css-js@^1.16.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.16.1.tgz#4b48b4354b0ff917a30488d95100fbf7219a3e80" + integrity sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg== + dependencies: + "@babel/runtime" "^7.1.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +screenfull@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" + integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4, semver@^7.6.0: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + +set-harmonic-interval@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" + integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +sonner@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/sonner/-/sonner-1.7.1.tgz#737110a3e6211d8d766442076f852ddde1725205" + integrity sha512-b6LHBfH32SoVasRFECrdY8p8s7hXPDn3OHUFbZZbiB1ctLS9Gdh6rpX2dVrpQA0kiL5jcRzDDldwwLkSKk3+QQ== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA== + +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + +space-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" + integrity sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q== + +stack-generator@^2.0.5: + version "2.0.10" + resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.10.tgz#8ae171e985ed62287d4f1ed55a1633b3fb53bb4d" + integrity sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ== + dependencies: + stackframe "^1.3.4" + +stackframe@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" + integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== + +stacktrace-gps@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz#0c40b24a9b119b20da4525c398795338966a2fb0" + integrity sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ== + dependencies: + source-map "0.5.6" + stackframe "^1.3.4" + +stacktrace-js@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" + integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== + dependencies: + error-stack-parser "^2.0.6" + stack-generator "^2.0.5" + stacktrace-gps "^3.0.4" + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + +stringify-entities@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.4.tgz#b3b79ef5f277cc4ac73caeb0236c5ba939b3a4f3" + integrity sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg== + dependencies: + character-entities-html4 "^2.0.0" + character-entities-legacy "^3.0.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-to-js@^1.0.0: + version "1.1.17" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.17.tgz#488b1558a8c1fd05352943f088cc3ce376813d83" + integrity sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA== + dependencies: + style-to-object "1.0.9" + +style-to-object@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.9.tgz#35c65b713f4a6dba22d3d0c61435f965423653f0" + integrity sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw== + dependencies: + inline-style-parser "0.2.4" + +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== + +stylis@^4.3.0: + version "4.3.6" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320" + integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ== + +sucrase@^3.35.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + 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" + ts-interface-checker "^0.1.9" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tabbable@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" + integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== + +tailwindcss@^3.4.0: + version "3.4.17" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.17.tgz#ae8406c0f96696a631c790768ff319d46d5e5a63" + integrity sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.6.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.2" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.6" + lilconfig "^3.1.3" + micromatch "^4.0.8" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.1.1" + postcss "^8.4.47" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.2" + postcss-nested "^6.2.0" + postcss-selector-parser "^6.1.2" + resolve "^1.22.8" + sucrase "^3.35.0" + +text-segmentation@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943" + integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw== + dependencies: + utrie "^1.0.2" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +throttle-debounce@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" + integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== + +through2@^0.6.3: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + integrity sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg== + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + +tinycolor2@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" + integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== + +tinyqueue@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08" + integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +trim-lines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" + integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== + +trough@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" + integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== + +ts-api-utils@^1.0.1, ts-api-utils@^1.3.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== + +ts-easing@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" + integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typescript@^5.7.3: + version "5.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6" + integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +unfetch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-3.1.2.tgz#dc271ef77a2800768f7b459673c5604b5101ef77" + integrity sha512-L0qrK7ZeAudGiKYw6nzFjnJ2D5WHblUBwmHIqtPS6oKUd+Hcpk7/hKsSmcHsTlpd1TbTNsiRBUKRq3bHLNIqIw== + +unfetch@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + +unified@^11.0.0: + version "11.0.5" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.5.tgz#f66677610a5c0a9ee90cab2b8d4d66037026d9e1" + integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== + dependencies: + "@types/unist" "^3.0.0" + bail "^2.0.0" + devlop "^1.0.0" + extend "^3.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^6.0.0" + +unist-util-is@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424" + integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4" + integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-stringify-position@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2" + integrity sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ== + dependencies: + "@types/unist" "^3.0.0" + +unist-util-visit-parents@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815" + integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + +unist-util-visit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6" + integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +use-callback-ref@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf" + integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg== + dependencies: + tslib "^2.0.0" + +use-isomorphic-layout-effect@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz#2f11a525628f56424521c748feabc2ffcc962fce" + integrity sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA== + +use-sidecar@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb" + integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + +usehooks-ts@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-3.1.0.tgz#156119f36efc85f1b1952616c02580f140950eca" + integrity sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw== + dependencies: + lodash.debounce "^4.0.8" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utrie@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645" + integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw== + dependencies: + base64-arraybuffer "^1.0.2" + +uuid@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" + integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +vfile-location@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.3.tgz#cb9eacd20f2b6426d19451e0eafa3d0a846225c3" + integrity sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg== + dependencies: + "@types/unist" "^3.0.0" + vfile "^6.0.0" + +vfile-message@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.3.tgz#87b44dddd7b70f0641c2e3ed0864ba73e2ea8df4" + integrity sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw== + dependencies: + "@types/unist" "^3.0.0" + unist-util-stringify-position "^4.0.0" + +vfile@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.3.tgz#3652ab1c496531852bf55a6bac57af981ebc38ab" + integrity sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q== + dependencies: + "@types/unist" "^3.0.0" + vfile-message "^4.0.0" + +vite@^4.5.3: + version "4.5.14" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.14.tgz#2e652bc1d898265d987d6543ce866ecd65fa4086" + integrity sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + +web-namespaces@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" + integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yaml@^2.3.4: + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zwitch@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== diff --git a/frontend/src/App.css b/frontend/src/App.css index 75e3dc15f..ca3bb08d8 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -11,7 +11,7 @@ outline-color: #d1d5db; } -.s3Container>button>div { +.s3Container > button > div { display: flex; flex-direction: column; align-items: center; @@ -68,49 +68,57 @@ display: block; margin: 7px auto; position: relative; - background: #FFF; - box-shadow: -12px 0 #FFF, 12px 0 #FFF; + background: #fff; + box-shadow: + -12px 0 #fff, + 12px 0 #fff; box-sizing: border-box; animation: shadowPulse 2s linear infinite; } @keyframes shadowPulse { 33% { - background: #FFF; - box-shadow: -12px 0 rgb(var(--theme-palette-primary-bg-strong)), 12px 0 #FFF; + background: #fff; + box-shadow: + -12px 0 rgb(var(--theme-palette-primary-bg-strong)), + 12px 0 #fff; } 66% { background: rgb(var(--theme-palette-primary-bg-strong)); - box-shadow: -12px 0 #FFF, 12px 0 #FFF; + box-shadow: + -12px 0 #fff, + 12px 0 #fff; } 100% { - background: #FFF; - box-shadow: -12px 0 #FFF, 12px 0 rgb(var(--theme-palette-primary-bg-strong)); + background: #fff; + box-shadow: + -12px 0 #fff, + 12px 0 rgb(var(--theme-palette-primary-bg-strong)); } } -.dropdownbtn{ +.dropdownbtn { background-color: #014063; color: white !important; border-radius: unset !important; width: 35px; padding: 0.5rem; } -.dropdownbtn:hover{ +.dropdownbtn:hover { background-color: #02293d !important; } -.graphbtn{ +.graphbtn { border-top-right-radius: 0px !important; border-bottom-right-radius: 0px !important; } -.dropdownbtn.darktheme{ - background-color: #51A6B1; +.dropdownbtn.darktheme { + background-color: #51a6b1; } -.dropdownbtn.small{ +.dropdownbtn.small { height: 24px; } -.darktheme:hover{ +.darktheme:hover { background-color: #44929c !important; } @@ -132,7 +140,7 @@ } .dropdownbtn.darktheme { - background-color: #51A6B1; + background-color: #51a6b1; } .dropdownbtn.small { @@ -143,7 +151,7 @@ background-color: #44929c !important; } -.ndl-dropzone>div { +.ndl-dropzone > div { padding-top: 10px !important; padding-bottom: 10px !important; } @@ -154,7 +162,6 @@ scrollbar-gutter: stable; } - .connectionmodal__input { width: 48.5%; margin-right: 1.5%; @@ -175,7 +182,7 @@ .connectionmodal__protocal__input { width: 25%; - display: inline-block + display: inline-block; } .connectionstatus__container { @@ -214,8 +221,8 @@ white-space: nowrap; } -.ndl-widget-content>div { - overflow-wrap: break-word +.ndl-widget-content > div { + overflow-wrap: break-word; } .word-break { @@ -230,13 +237,13 @@ } .ndl-type-checkbox, -.ndl-label-before>span { +.ndl-label-before > span { font-weight: 600; font-size: larger; } .ndl-upload-img-wrapper { - background: url("./assets/images/dropzone.svg"); + background: url('./assets/images/dropzone.svg'); background-repeat: no-repeat; background-position: center; } @@ -257,7 +264,7 @@ container-type: size; } -.source-container>* { +.source-container > * { width: 100%; } @@ -274,7 +281,6 @@ .outline-dashed .wikipedia-div { padding: 12px; } - } @container (min-height:400px) and (max-height:500px) { @@ -290,7 +296,6 @@ .outline-dashed .wikipedia-div { padding: 10px; } - } @container (max-height:300px) { @@ -311,7 +316,7 @@ margin-bottom: 5px !important; } - .imageBg>div { + .imageBg > div { padding: 5px; } @@ -365,7 +370,7 @@ } .ndl-modal-root { - z-index: 39 !important; + z-index: 10000 !important; } .tbody-dark .ndl-data-grid-tr:hover { @@ -393,14 +398,13 @@ .layout-wrapper { display: grid; grid-template-rows: auto; - grid-template-columns: 64px 1fr minmax(min-content,4fr) 1.1fr 64px; + grid-template-columns: 64px 1fr minmax(min-content, 4fr) 1.1fr 64px; max-height: calc(100vh - 58px); max-width: 100%; } .layout-wrapper.drawerdropzoneclosed { grid-template-columns: 64px 4fr 1.1fr 64px; - } .layout-wrapper.drawerchatbotclosed { @@ -419,27 +423,24 @@ height: 100%; } -@media screen and (min-width:1025px) and (max-width:1440px){ - .layout-wrapper{ - grid-template-columns: 64px 1fr minmax(min-content,4fr) minmax(min-content,2fr) 64px; - - } +@media screen and (min-width: 1025px) and (max-width: 1440px) { + .layout-wrapper { + grid-template-columns: 64px 1fr minmax(min-content, 4fr) minmax(min-content, 2fr) 64px; + } } -@media screen and (min-width:1536px) and (max-width:2560px) { +@media screen and (min-width: 1536px) and (max-width: 2560px) { .layout-wrapper { grid-template-columns: 64px 1fr minmax(min-content, 6.5fr) minmax(max-content, 1fr) 64px; - } } .sidenav-container { height: calc(100vh - 58px); min-height: 200px; - display: flex + display: flex; } - .resource-sections.blur-sm { filter: blur(2px); } @@ -468,18 +469,18 @@ max-height: fit-content; height: 150px; padding: 10px; - width:100%; + width: 100%; } @keyframes highlightAnimation { 0% { - background-color:rgb(var(--theme-palette-neutral-bg-weak)); + background-color: rgb(var(--theme-palette-neutral-bg-weak)); border-color: rgb(var(--theme-palette-primary-bg-weak)); transform: scale(1); } 50% { - background-color:rgb(var(--theme-palette-neutral-bg-weak)); + background-color: rgb(var(--theme-palette-neutral-bg-weak)); border-color: rgb(var(--theme-palette-primary-bg-strong)); transform: scale(1.05); } @@ -495,4 +496,3 @@ animation: highlightAnimation 1.5s ease-in-out; border: 2px solid rgb(var(--theme-palette-primary-bg-strong)); } - diff --git a/frontend/src/components/Graph/GraphViewModal.tsx b/frontend/src/components/Graph/GraphViewModal.tsx index 114b8471b..76ad6b61b 100644 --- a/frontend/src/components/Graph/GraphViewModal.tsx +++ b/frontend/src/components/Graph/GraphViewModal.tsx @@ -180,6 +180,8 @@ const GraphViewModal: React.FunctionComponent = ({ useEffect(() => { if (open) { + // Clear any stuck popups that might be covering the modal + document.querySelectorAll('.popup').forEach((el) => el.remove()); setLoading(true); setGraphType([]); if (viewPoint !== graphLabels.chatInfoView) { @@ -345,6 +347,8 @@ const GraphViewModal: React.FunctionComponent = ({ // when modal closes reset all states to default const onClose = () => { + // Clear any stuck popups + document.querySelectorAll('.popup').forEach((el) => el.remove()); graphQueryAbortControllerRef?.current?.abort(); setStatus('unknown'); setStatusMessage(''); diff --git a/frontend/src/components/Graph/SchemaViz.tsx b/frontend/src/components/Graph/SchemaViz.tsx index 0bb7d9762..e9e023ea9 100644 --- a/frontend/src/components/Graph/SchemaViz.tsx +++ b/frontend/src/components/Graph/SchemaViz.tsx @@ -70,6 +70,8 @@ const SchemaViz: React.FunctionComponent = ({ useEffect(() => { if (open) { + // Clear any stuck popups that might be covering the modal + document.querySelectorAll('.popup').forEach((el) => el.remove()); if (view !== 'viz') { setLoading(true); const { nodes, relationships, scheme } = userDefinedGraphSchema( @@ -171,6 +173,8 @@ const SchemaViz: React.FunctionComponent = ({ // when modal closes reset all states to default const onClose = () => { + // Clear any stuck popups + document.querySelectorAll('.popup').forEach((el) => el.remove()); graphQueryAbortControllerRef?.current?.abort(); setStatus('unknown'); setStatusMessage(''); diff --git a/frontend/src/components/UI/HoverableLink.tsx b/frontend/src/components/UI/HoverableLink.tsx index 4c320a14a..8143c9048 100644 --- a/frontend/src/components/UI/HoverableLink.tsx +++ b/frontend/src/components/UI/HoverableLink.tsx @@ -15,6 +15,20 @@ const HoverableLink: React.FC = ({ url, children }) => { } return () => clearTimeout(timer); }, [hovering, url]); + + // Add global click handler to close popup when clicking elsewhere + useEffect(() => { + const handleGlobalClick = () => { + setHovering(false); + }; + + if (hovering) { + document.addEventListener('click', handleGlobalClick); + return () => { + document.removeEventListener('click', handleGlobalClick); + }; + } + }, [hovering]); const handleMouseEnter = (event: React.MouseEvent) => { setHovering(true); setMousePosition({ x: event.clientX, y: event.clientY }); diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 03f6418b3..2e517616b 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@ampproject/remapping@^2.2.0": +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== @@ -16,26 +16,18 @@ "@jridgewell/trace-mapping" "^0.3.24" "@auth0/auth0-react@^2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@auth0/auth0-react/-/auth0-react-2.2.4.tgz#7f21751a219d4e0e019141819f00e76e436176dd" - integrity sha512-l29PQC0WdgkCoOc6WeMAY26gsy/yXJICW0jHfj0nz8rZZphYKrLNqTRWFFCMJY+sagza9tSgB1kG/UvQYgGh9A== + version "2.4.0" + resolved "https://registry.yarnpkg.com/@auth0/auth0-react/-/auth0-react-2.4.0.tgz#a0209635cd756adb9d471ad0e8c929d62eeaffdb" + integrity sha512-5bt3sO9FVupNM15IpqyYu/2OPHpLI5El7RgWLQXZOPbnCBbtl+VgdHR+H2NfhNQ4SqQtC/5uKbHWafcVcsxkiw== dependencies: - "@auth0/auth0-spa-js" "^2.1.3" + "@auth0/auth0-spa-js" "^2.2.0" -"@auth0/auth0-spa-js@^2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@auth0/auth0-spa-js/-/auth0-spa-js-2.1.3.tgz#aabf6f439e41edbeef0cf4766ad754e5b47616e5" - integrity sha512-NMTBNuuG4g3rame1aCnNS5qFYIzsTUV5qTFPRfTyYFS1feS6jsCBR+eTq9YkxCp1yuoM2UIcjunPaoPl77U9xQ== - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" - integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== - dependencies: - "@babel/highlight" "^7.24.7" - picocolors "^1.0.0" +"@auth0/auth0-spa-js@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@auth0/auth0-spa-js/-/auth0-spa-js-2.3.0.tgz#fcbbe31e31e8e98c4e7b25a8d043eac8c01f73bf" + integrity sha512-zAW6w79UO+G1+3AxboVQIUIZy05xluSOb1ymGg2dqG0pIi0JxEtZGec05BOf2LJ9SehzW4WeCYUQsYD9BjrVpQ== -"@babel/code-frame@^7.27.1": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== @@ -45,50 +37,40 @@ picocolors "^1.1.1" "@babel/compat-data@^7.27.2": - version "7.27.3" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.27.3.tgz#cc49c2ac222d69b889bf34c795f537c0c6311111" - integrity sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw== + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790" + integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw== -"@babel/core@^7.26.10": - version "7.27.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.27.4.tgz#cc1fc55d0ce140a1828d1dd2a2eba285adbfb3ce" - integrity sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g== +"@babel/core@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4" + integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.27.3" + "@babel/generator" "^7.28.0" "@babel/helper-compilation-targets" "^7.27.2" "@babel/helper-module-transforms" "^7.27.3" - "@babel/helpers" "^7.27.4" - "@babel/parser" "^7.27.4" + "@babel/helpers" "^7.27.6" + "@babel/parser" "^7.28.0" "@babel/template" "^7.27.2" - "@babel/traverse" "^7.27.4" - "@babel/types" "^7.27.3" + "@babel/traverse" "^7.28.0" + "@babel/types" "^7.28.0" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.25.0": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e" - integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw== +"@babel/generator@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2" + integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg== dependencies: - "@babel/types" "^7.25.0" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" - -"@babel/generator@^7.27.3": - version "7.27.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.27.3.tgz#ef1c0f7cfe3b5fc8cbb9f6cc69f93441a68edefc" - integrity sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q== - dependencies: - "@babel/parser" "^7.27.3" - "@babel/types" "^7.27.3" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" + "@babel/parser" "^7.28.0" + "@babel/types" "^7.28.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" "@babel/helper-compilation-targets@^7.27.2": @@ -102,15 +84,12 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-module-imports@^7.16.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== -"@babel/helper-module-imports@^7.27.1": +"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== @@ -132,21 +111,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== -"@babel/helper-string-parser@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" - integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== - "@babel/helper-string-parser@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== -"@babel/helper-validator-identifier@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" - integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== - "@babel/helper-validator-identifier@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" @@ -157,65 +126,39 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== -"@babel/helpers@^7.27.4": - version "7.27.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.4.tgz#c79050c6a0e41e095bfc96d469c85431e9ed7fe7" - integrity sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ== +"@babel/helpers@^7.27.6": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.2.tgz#80f0918fecbfebea9af856c419763230040ee850" + integrity sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw== dependencies: "@babel/template" "^7.27.2" - "@babel/types" "^7.27.3" + "@babel/types" "^7.28.2" -"@babel/highlight@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" - integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.27.2", "@babel/parser@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== dependencies: - "@babel/helper-validator-identifier" "^7.24.7" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" + "@babel/types" "^7.28.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.0", "@babel/parser@^7.25.3": - version "7.25.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065" - integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw== - dependencies: - "@babel/types" "^7.25.2" - -"@babel/parser@^7.27.2", "@babel/parser@^7.27.3", "@babel/parser@^7.27.4": - version "7.27.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.4.tgz#f92e89e4f51847be05427285836fc88341c956df" - integrity sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g== - dependencies: - "@babel/types" "^7.27.3" - -"@babel/plugin-transform-react-jsx-self@^7.25.9": +"@babel/plugin-transform-react-jsx-self@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz#af678d8506acf52c577cac73ff7fe6615c85fc92" integrity sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw== dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-react-jsx-source@^7.25.9": +"@babel/plugin-transform-react-jsx-source@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz#dcfe2c24094bb757bf73960374e7c55e434f19f0" integrity sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw== dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.27.1", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": - version "7.27.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.4.tgz#a91ec580e6c00c67118127777c316dfd5a5a6abf" - integrity sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA== - -"@babel/template@^7.25.0": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" - integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.25.0" - "@babel/types" "^7.25.0" +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.28.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473" + integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA== "@babel/template@^7.27.2": version "7.27.2" @@ -226,53 +169,31 @@ "@babel/parser" "^7.27.2" "@babel/types" "^7.27.1" -"@babel/traverse@^7.24.7": - version "7.25.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.3.tgz#f1b901951c83eda2f3e29450ce92743783373490" - integrity sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.0" - "@babel/parser" "^7.25.3" - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.2" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.27.4": - version "7.27.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.27.4.tgz#b0045ac7023c8472c3d35effd7cc9ebd638da6ea" - integrity sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA== +"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b" + integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg== dependencies: "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.27.3" - "@babel/parser" "^7.27.4" + "@babel/generator" "^7.28.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.0" "@babel/template" "^7.27.2" - "@babel/types" "^7.27.3" + "@babel/types" "^7.28.0" debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125" - integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q== - dependencies: - "@babel/helper-string-parser" "^7.24.8" - "@babel/helper-validator-identifier" "^7.24.7" - to-fast-properties "^2.0.0" -"@babel/types@^7.27.1", "@babel/types@^7.27.3": - version "7.27.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.3.tgz#c0257bedf33aad6aad1f406d35c44758321eb3ec" - integrity sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.28.0", "@babel/types@^7.28.2": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b" + integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ== dependencies: "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.27.1" "@dnd-kit/accessibility@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz#1054e19be276b5f1154ced7947fc0cb5d99192e0" - integrity sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ== + version "3.1.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz#3b4202bd6bb370a0730f6734867785919beac6af" + integrity sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw== dependencies: tslib "^2.0.0" @@ -300,7 +221,29 @@ dependencies: tslib "^2.0.0" -"@emotion/babel-plugin@^11.12.0", "@emotion/babel-plugin@^11.13.5": +"@emnapi/core@^1.4.3": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.5.tgz#bfbb0cbbbb9f96ec4e2c4fd917b7bbe5495ceccb" + integrity sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q== + dependencies: + "@emnapi/wasi-threads" "1.0.4" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.5.tgz#c67710d0661070f38418b6474584f159de38aba9" + integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.0.4", "@emnapi/wasi-threads@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz#703fc094d969e273b1b71c292523b2f792862bf4" + integrity sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g== + dependencies: + tslib "^2.4.0" + +"@emotion/babel-plugin@^11.13.5": version "11.13.5" resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz#eab8d65dbded74e0ecfd28dc218e75607c4e7bc0" integrity sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ== @@ -317,7 +260,7 @@ source-map "^0.5.7" stylis "4.2.0" -"@emotion/cache@^11.11.0", "@emotion/cache@^11.13.0", "@emotion/cache@^11.13.5", "@emotion/cache@^11.4.0": +"@emotion/cache@^11.13.5", "@emotion/cache@^11.14.0", "@emotion/cache@^11.4.0": version "11.14.0" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.14.0.tgz#ee44b26986eeb93c8be82bb92f1f7a9b21b2ed76" integrity sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA== @@ -334,9 +277,9 @@ integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== "@emotion/is-prop-valid@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz#bd84ba972195e8a2d42462387581560ef780e4e2" - integrity sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ== + version "1.3.1" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz#8d5cf1132f836d7adbe42cf0b49df7816fc88240" + integrity sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw== dependencies: "@emotion/memoize" "^0.9.0" @@ -346,20 +289,20 @@ integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== "@emotion/react@^11.8.1": - version "11.13.0" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.0.tgz#a9ebf827b98220255e5760dac89fa2d38ca7b43d" - integrity sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ== + version "11.14.0" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.14.0.tgz#cfaae35ebc67dd9ef4ea2e9acc6cd29e157dd05d" + integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.12.0" - "@emotion/cache" "^11.13.0" - "@emotion/serialize" "^1.3.0" - "@emotion/use-insertion-effect-with-fallbacks" "^1.1.0" - "@emotion/utils" "^1.4.0" + "@emotion/babel-plugin" "^11.13.5" + "@emotion/cache" "^11.14.0" + "@emotion/serialize" "^1.3.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.2.0" + "@emotion/utils" "^1.4.2" "@emotion/weak-memoize" "^0.4.0" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@^1.3.0", "@emotion/serialize@^1.3.3": +"@emotion/serialize@^1.3.3": version "1.3.3" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.3.tgz#d291531005f17d704d0463a032fe679f376509e8" integrity sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA== @@ -376,9 +319,9 @@ integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== "@emotion/styled@^11.14.0": - version "11.14.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.14.0.tgz#f47ca7219b1a295186d7661583376fcea95f0ff3" - integrity sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA== + version "11.14.1" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.14.1.tgz#8c34bed2948e83e1980370305614c20955aacd1c" + integrity sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw== dependencies: "@babel/runtime" "^7.18.3" "@emotion/babel-plugin" "^11.13.5" @@ -392,12 +335,12 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== -"@emotion/use-insertion-effect-with-fallbacks@^1.1.0", "@emotion/use-insertion-effect-with-fallbacks@^1.2.0": +"@emotion/use-insertion-effect-with-fallbacks@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz#8a8cb77b590e09affb960f4ff1e9a89e532738bf" integrity sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg== -"@emotion/utils@^1.4.0", "@emotion/utils@^1.4.2": +"@emotion/utils@^1.4.2": version "1.4.2" resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.2.tgz#6df6c45881fcb1c412d6688a311a98b7f59c1b52" integrity sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA== @@ -518,16 +461,16 @@ integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== dependencies: - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.3" -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.11.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" - integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== "@eslint/eslintrc@^2.1.4": version "2.1.4" @@ -544,33 +487,40 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@floating-ui/core@^1.6.0": - version "1.6.7" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.7.tgz#7602367795a390ff0662efd1c7ae8ca74e75fb12" - integrity sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g== +"@floating-ui/core@^1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7" + integrity sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w== dependencies: - "@floating-ui/utils" "^0.2.7" + "@floating-ui/utils" "^0.2.10" -"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.0.1": - version "1.6.10" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.10.tgz#b74c32f34a50336c86dcf1f1c845cf3a39e26d6f" - integrity sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A== +"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.0.1", "@floating-ui/dom@^1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.3.tgz#6174ac3409e6a064bbdf1f4bb07188ee9461f8cf" + integrity sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag== dependencies: - "@floating-ui/core" "^1.6.0" - "@floating-ui/utils" "^0.2.7" + "@floating-ui/core" "^1.7.3" + "@floating-ui/utils" "^0.2.10" -"@floating-ui/react-dom@2.1.2", "@floating-ui/react-dom@^2.1.2": +"@floating-ui/react-dom@2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.2.tgz#a1349bbf6a0e5cb5ded55d023766f20a4d439a31" integrity sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A== dependencies: "@floating-ui/dom" "^1.0.0" +"@floating-ui/react-dom@^2.1.2": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.5.tgz#d11e3726d2eb385d8cf3216348742907c1d49fcf" + integrity sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q== + dependencies: + "@floating-ui/dom" "^1.7.3" + "@floating-ui/react@0.26.24": version "0.26.24" resolved "https://registry.yarnpkg.com/@floating-ui/react/-/react-0.26.24.tgz#072b9dfeca4e79ef4e3000ef1c28e0ffc86f4ed4" @@ -589,66 +539,63 @@ "@floating-ui/utils" "^0.2.8" tabbable "^6.0.0" -"@floating-ui/utils@^0.2.7": - version "0.2.7" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.7.tgz#d0ece53ce99ab5a8e37ebdfe5e32452a2bfc073e" - integrity sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA== - -"@floating-ui/utils@^0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" - integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== +"@floating-ui/utils@^0.2.10", "@floating-ui/utils@^0.2.8": + version "0.2.10" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" + integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== -"@formatjs/ecma402-abstract@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz#39197ab90b1c78b7342b129a56a7acdb8f512e17" - integrity sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g== +"@formatjs/ecma402-abstract@2.3.4": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz#e90c5a846ba2b33d92bc400fdd709da588280fbc" + integrity sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA== dependencies: - "@formatjs/intl-localematcher" "0.5.4" - tslib "^2.4.0" + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/intl-localematcher" "0.6.1" + decimal.js "^10.4.3" + tslib "^2.8.0" -"@formatjs/fast-memoize@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz#33bd616d2e486c3e8ef4e68c99648c196887802b" - integrity sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA== +"@formatjs/fast-memoize@2.2.7": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz#707f9ddaeb522a32f6715bb7950b0831f4cc7b15" + integrity sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ== dependencies: - tslib "^2.4.0" + tslib "^2.8.0" -"@formatjs/icu-messageformat-parser@2.7.8": - version "2.7.8" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz#f6d7643001e9bb5930d812f1f9a9856f30fa0343" - integrity sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA== +"@formatjs/icu-messageformat-parser@2.11.2": + version "2.11.2" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz#85aea211bea40aa81ee1d44ac7accc3cf5500a73" + integrity sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA== dependencies: - "@formatjs/ecma402-abstract" "2.0.0" - "@formatjs/icu-skeleton-parser" "1.8.2" - tslib "^2.4.0" + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/icu-skeleton-parser" "1.8.14" + tslib "^2.8.0" -"@formatjs/icu-skeleton-parser@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz#2252c949ae84ee66930e726130ea66731a123c9f" - integrity sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q== +"@formatjs/icu-skeleton-parser@1.8.14": + version "1.8.14" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz#b9581d00363908efb29817fdffc32b79f41dabe5" + integrity sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ== dependencies: - "@formatjs/ecma402-abstract" "2.0.0" - tslib "^2.4.0" + "@formatjs/ecma402-abstract" "2.3.4" + tslib "^2.8.0" -"@formatjs/intl-localematcher@0.5.4": - version "0.5.4" - resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz#caa71f2e40d93e37d58be35cfffe57865f2b366f" - integrity sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g== +"@formatjs/intl-localematcher@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz#25dc30675320bf65a9d7f73876fc1e4064c0e299" + integrity sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg== dependencies: - tslib "^2.4.0" + tslib "^2.8.0" "@heroicons/react@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.5.tgz#1e13f34976cc542deae92353c01c8b3d7942e9ba" integrity sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA== -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: - "@humanwhocodes/object-schema" "^2.0.2" + "@humanwhocodes/object-schema" "^2.0.3" debug "^4.3.1" minimatch "^3.0.5" @@ -657,47 +604,53 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.2": +"@humanwhocodes/object-schema@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== -"@internationalized/date@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.6.0.tgz#b30d43030bfed1855f20c9503606926d75bfdf64" - integrity sha512-+z6ti+CcJnRlLHok/emGEsWQhe7kfSmEW+/6qCzvKY67YPh7YOBfvc7+/+NXq+zJlbArg30tYpqLjNgcAYv2YQ== +"@internationalized/date@^3.8.2": + version "3.8.2" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.8.2.tgz#977620c1407cc6830fd44cb505679d23c599e119" + integrity sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA== dependencies: "@swc/helpers" "^0.5.0" -"@internationalized/message@^3.1.6": - version "3.1.6" - resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.6.tgz#e5a832788a17214bfb3e5bbf5f0e23ed2f568ad7" - integrity sha512-JxbK3iAcTIeNr1p0WIFg/wQJjIzJt9l/2KNY/48vXV7GRGZSv3zMxJsce008fZclk2cDC8y0Ig3odceHO7EfNQ== +"@internationalized/message@^3.1.8": + version "3.1.8" + resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.8.tgz#7181e8178f0868535f4507a573bf285e925832cb" + integrity sha512-Rwk3j/TlYZhn3HQ6PyXUV0XP9Uv42jqZGNegt0BXlxjE6G3+LwHjbQZAGHhCnCPdaA6Tvd3ma/7QzLlLkJxAWA== dependencies: "@swc/helpers" "^0.5.0" intl-messageformat "^10.1.0" -"@internationalized/number@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.0.tgz#dc6ba20c41b25eb605f1d5cac7d8668e9022c224" - integrity sha512-PtrRcJVy7nw++wn4W2OuePQQfTqDzfusSuY1QTtui4wa7r+rGVtR75pO8CyKvHvzyQYi3Q1uO5sY0AsB4e65Bw== +"@internationalized/number@^3.6.4": + version "3.6.4" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.4.tgz#3ab593fec5e87654fdece0a3238cdc9d0eedff8a" + integrity sha512-P+/h+RDaiX8EGt3shB9AYM1+QgkvHmJ5rKi4/59k4sg9g58k9rqsRW0WxRO7jCoHyvVbFRRFKmVTdFYdehrxHg== dependencies: "@swc/helpers" "^0.5.0" -"@internationalized/string@^3.2.4", "@internationalized/string@^3.2.5": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.5.tgz#2f387b256e79596a2e62ddd5e15c619fe241189c" - integrity sha512-rKs71Zvl2OKOHM+mzAFMIyqR5hI1d1O6BBkMK2/lkfg3fkmVh9Eeg0awcA8W2WqYqDOv6a86DIOlFpggwLtbuw== +"@internationalized/string@^3.2.4", "@internationalized/string@^3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.7.tgz#76ae10f1e6e1fdaec7d0028a3f807d37a71bd2dd" + integrity sha512-D4OHBjrinH+PFZPvfCXvG28n2LSykWcJ7GIioQL+ok0LON15SdfoUssoHzzOUmVZLbRoREsQXVzA6r8JKsbP6A== dependencies: "@swc/helpers" "^0.5.0" -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" + minipass "^7.0.4" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.12" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" + integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" "@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/resolve-uri@^3.1.0": @@ -705,20 +658,15 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" + integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.29" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" + integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" @@ -735,90 +683,100 @@ dependencies: "@lukeed/csprng" "^1.1.0" -"@mui/core-downloads-tracker@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.6.tgz#f029e12ffda8eb79838cc85897f03a628010037c" - integrity sha512-kytg6LheUG42V8H/o/Ptz3olSO5kUXW9zF0ox18VnblX6bO2yif1FPItgc3ey1t5ansb1+gbe7SatntqusQupg== +"@mui/core-downloads-tracker@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.18.0.tgz#85019a8704b0f63305fc5600635ee663810f2b66" + integrity sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA== "@mui/material@^5.15.10": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.16.6.tgz#c7d695f4a9a473052dc086e64471d0435b7e4a52" - integrity sha512-0LUIKBOIjiFfzzFNxXZBRAyr9UQfmTAFzbt6ziOU2FDXhorNN2o3N9/32mNJbCA8zJo2FqFU6d3dtoqUDyIEfA== + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.18.0.tgz#71e72d52338252edc6f8d9461e04fdf0d61905cd" + integrity sha512-bbH/HaJZpFtXGvWg3TsBWG4eyt3gah3E7nCNU8GLyRjVoWcA91Vm/T+sjHfUcwgJSw9iLtucfHBoq+qW/T30aA== dependencies: "@babel/runtime" "^7.23.9" - "@mui/core-downloads-tracker" "^5.16.6" - "@mui/system" "^5.16.6" - "@mui/types" "^7.2.15" - "@mui/utils" "^5.16.6" + "@mui/core-downloads-tracker" "^5.18.0" + "@mui/system" "^5.18.0" + "@mui/types" "~7.2.15" + "@mui/utils" "^5.17.1" "@popperjs/core" "^2.11.8" "@types/react-transition-group" "^4.4.10" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" - react-is "^18.3.1" + react-is "^19.0.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.16.6.tgz#547671e7ae3f86b68d1289a0b90af04dfcc1c8c9" - integrity sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw== +"@mui/private-theming@^5.17.1": + version "5.17.1" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.17.1.tgz#b4b6fbece27830754ef78186e3f1307dca42f295" + integrity sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ== dependencies: "@babel/runtime" "^7.23.9" - "@mui/utils" "^5.16.6" + "@mui/utils" "^5.17.1" prop-types "^15.8.1" -"@mui/styled-engine@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.16.6.tgz#60110c106dd482dfdb7e2aa94fd6490a0a3f8852" - integrity sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g== +"@mui/styled-engine@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.18.0.tgz#914cca1385bb33ce0cde31721f529c8bd7fa301c" + integrity sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg== dependencies: "@babel/runtime" "^7.23.9" - "@emotion/cache" "^11.11.0" + "@emotion/cache" "^11.13.5" + "@emotion/serialize" "^1.3.3" csstype "^3.1.3" prop-types "^15.8.1" "@mui/styled-engine@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-7.1.0.tgz#3bf1d7856b98934585f7d03582bd74073db2a4b4" - integrity sha512-m0mJ0c6iRC+f9hMeRe0W7zZX1wme3oUX0+XTVHjPG7DJz6OdQ6K/ggEOq7ZdwilcpdsDUwwMfOmvO71qDkYd2w== + version "7.3.1" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-7.3.1.tgz#c8fbfd5636376bf8ded8626a2423fdc53ede6343" + integrity sha512-Nqo6OHjvJpXJ1+9TekTE//+8RybgPQUKwns2Lh0sq+8rJOUSUKS3KALv4InSOdHhIM9Mdi8/L7LTF1/Ky6D6TQ== dependencies: - "@babel/runtime" "^7.27.1" - "@emotion/cache" "^11.13.5" + "@babel/runtime" "^7.28.2" + "@emotion/cache" "^11.14.0" "@emotion/serialize" "^1.3.3" "@emotion/sheet" "^1.4.0" csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.16.6.tgz#2dabe63d2e45816ce611c40d6e3f79b9c2ccbcd7" - integrity sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw== +"@mui/system@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.18.0.tgz#e55331203a40584b26c5a855a07949ac8973bfb6" + integrity sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw== dependencies: "@babel/runtime" "^7.23.9" - "@mui/private-theming" "^5.16.6" - "@mui/styled-engine" "^5.16.6" - "@mui/types" "^7.2.15" - "@mui/utils" "^5.16.6" + "@mui/private-theming" "^5.17.1" + "@mui/styled-engine" "^5.18.0" + "@mui/types" "~7.2.15" + "@mui/utils" "^5.17.1" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" -"@mui/types@^7.2.15": - version "7.2.15" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.15.tgz#dadd232fe9a70be0d526630675dff3b110f30b53" - integrity sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q== +"@mui/types@~7.2.15": + version "7.2.24" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.24.tgz#5eff63129d9c29d80bbf2d2e561bd0690314dec2" + integrity sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw== -"@mui/utils@^5.16.6": - version "5.16.6" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.16.6.tgz#905875bbc58d3dcc24531c3314a6807aba22a711" - integrity sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA== +"@mui/utils@^5.17.1": + version "5.17.1" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.17.1.tgz#72ba4ffa79f7bdf69d67458139390f18484b6e6b" + integrity sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg== dependencies: "@babel/runtime" "^7.23.9" - "@mui/types" "^7.2.15" + "@mui/types" "~7.2.15" "@types/prop-types" "^15.7.12" clsx "^2.1.1" prop-types "^15.8.1" - react-is "^18.3.1" + react-is "^19.0.0" + +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" "@neo4j-bloom/dagre@^0.8.14": version "0.8.14" @@ -837,24 +795,30 @@ chroma-js "2.4.2" "@neo4j-ndl/base@^3.2.9": - version "3.2.9" - resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-3.2.9.tgz#19a0e1dcf5569feb2311780da62b9e0cff028ade" - integrity sha512-TQxhTbFJjjUHwxJnhROmta2ZiSDnrJa/zofoFHTF2eefnMufeFUOSAw4ELnjSYSRGRDuWJSRpBRXh5EMiOf8BA== + version "3.7.19" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/base/-/base-3.7.19.tgz#7a79b97ca89b9a111eb72a767c88b054be9bcc85" + integrity sha512-YXyO7VRppuwthxvRUTnfsr9uY9C7G0QHSTkqdVoBc/o7+AURxBf24nrHqbq2yhh6ba/cu/CZSwX3QdgXh47l6A== "@neo4j-ndl/react@^3.2.18": - version "3.2.18" - resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-3.2.18.tgz#1510cfba9cbb8a142376a8a6322b7e3330728c5c" - integrity sha512-ql8E7kNI+fq6e0akJZVawp2XAmJ6kRGLQzX/NUE4nmmCE0dzubRHqbiJOZrVLuEtlwUiGQc5xU5/gjio+QpsJA== + version "3.9.1" + resolved "https://registry.yarnpkg.com/@neo4j-ndl/react/-/react-3.9.1.tgz#20a3a74fcccac897e89f92d8fb06fefee0752d03" + integrity sha512-fNRevCccg06mU9UaVZeQC/a9Tr6IFKrEAKkbjgenXTHo8zJlfn+w30fqHNgHfMMV/VUtnUuBi8M4fIVguvb/mw== dependencies: "@dnd-kit/core" "6.1.0" "@dnd-kit/sortable" "8.0.0" "@floating-ui/react" "0.26.24" "@floating-ui/react-dom" "2.1.2" "@heroicons/react" "2.1.5" + "@neo4j-devtools/word-color" "^0.0.8" + "@neo4j-nvl/base" "0.3.9" + "@neo4j-nvl/interaction-handlers" "0.3.9" + "@neo4j-nvl/react" "0.3.9" + "@uiw/react-color" "2.5.4" classnames "2.5.1" date-fns "4.1.0" detect-browser "5.3.0" - re-resizable "6.10.0" + eyedropper-polyfill "1.0.2" + re-resizable "6.11.2" react-aria "3.35.0" react-datepicker "6.9.0" react-dropzone "14.2.9" @@ -867,12 +831,12 @@ tinycolor2 "1.6.0" usehooks-ts "3.1.0" -"@neo4j-nvl/base@0.3.8", "@neo4j-nvl/base@^0.3.6": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@neo4j-nvl/base/-/base-0.3.8.tgz#ad9d6ddd7da692092a5e46a55cfcb5a4b99c9f9a" - integrity sha512-h+tVJtUoKxweSot+FTRypQ3oUGeR2BBoTDFMAIPKPlq7SegtHDRGbXunayelgBWAnOVUovWNN27HJHSZoZ1LwA== +"@neo4j-nvl/base@0.3.9", "@neo4j-nvl/base@^0.3.6": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/base/-/base-0.3.9.tgz#19b9832f4c2d011f781f12f652b9c54ac77f7326" + integrity sha512-tQsMb5X7tT8KzCkDqgbeSSMFDt6Fr7180zKCCS7ttwq9zIuN4+JbNyIJ6E7Z+Sd+2yDsWbC0pWWCKZje6U4Jrg== dependencies: - "@neo4j-nvl/layout-workers" "0.3.8" + "@neo4j-nvl/layout-workers" "0.3.9" "@segment/analytics-next" "^1.70.0" color-string "^1.9.1" d3-force "^3.0.0" @@ -886,19 +850,19 @@ tinycolor2 "1.6.0" uuid "^8.3.2" -"@neo4j-nvl/interaction-handlers@0.3.8": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@neo4j-nvl/interaction-handlers/-/interaction-handlers-0.3.8.tgz#e7d03f322c59d6083b1b4881f6b7f8ab65f9dd58" - integrity sha512-hOhv7l6e/Kb7yv12HUbz1CtsFUML8w/ZW72e5PGeEpkZTEGIdNGJNPdY5cpl3oobNNUuPPx/9/kfd0TeZMEiNw== +"@neo4j-nvl/interaction-handlers@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/interaction-handlers/-/interaction-handlers-0.3.9.tgz#412e68bbeb1a2b60b892be5e8ceb05ecbc1f88d8" + integrity sha512-rpPJEj6NWZJp7jqaVs//MQQd6q8jRhlDtJg0WSbcS3gXw+b98ODnVTqczw7ZeKpmmtZWc8dnvtApe5EleLrLwg== dependencies: - "@neo4j-nvl/base" "0.3.8" + "@neo4j-nvl/base" "0.3.9" concaveman "^1.2.1" lodash "4.17.21" -"@neo4j-nvl/layout-workers@0.3.8": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@neo4j-nvl/layout-workers/-/layout-workers-0.3.8.tgz#ff54d79ce74793264849b3cfaa343ed33af96c85" - integrity sha512-koLseX8Q8nlySTrsZu7EWpRM1AajUOPnwWF16e5MrStRT+CwV5cKipEHmFXbFg/uLycN7PY/72VOYAVG3dR72A== +"@neo4j-nvl/layout-workers@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/layout-workers/-/layout-workers-0.3.9.tgz#992cb1ad3a08f68f89e1eda820a59d9b4091eedd" + integrity sha512-3DHSL7Cb5Zcs3Aue5RmFaJsxTNXd5AILepwdyQFE0A/gEmVpmBMbJE2QnBGCOQhUXf3hpW3QGz8Z0DkZzhHPuw== dependencies: "@neo4j-bloom/dagre" "^0.8.14" bin-pack "^1.0.2" @@ -906,13 +870,13 @@ cytoscape-cose-bilkent "^4.1.0" graphlib "^2.1.8" -"@neo4j-nvl/react@^0.3.8": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@neo4j-nvl/react/-/react-0.3.8.tgz#f4bad8956acb5eb9c1b7f2427f1b020264a8b75d" - integrity sha512-heplhpycpsq7c+xcjC9VjQDSJWmtf1TrkUt1E4G8xVd3zF7oQjKr38cXBWYWpO3mfqFn8CCLMvO+hXQ12/mpXA== +"@neo4j-nvl/react@0.3.9", "@neo4j-nvl/react@^0.3.8": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@neo4j-nvl/react/-/react-0.3.9.tgz#086150940638ba6f421cbb4e0294e57538428bcb" + integrity sha512-ZSxv66MWPAm29YdvlSHEjbI81YxTh/brTT56HsNQOhDWqPl5ebcAaNXtx6l4AWpb2jsi6EPcGKf1kqblEWdbyg== dependencies: - "@neo4j-nvl/base" "0.3.8" - "@neo4j-nvl/interaction-handlers" "0.3.8" + "@neo4j-nvl/base" "0.3.9" + "@neo4j-nvl/interaction-handlers" "0.3.9" lodash "4.17.21" react "^18.2.0" react-dom "^18.2.0" @@ -944,1085 +908,1082 @@ integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@react-aria/breadcrumbs@^3.5.17": - version "3.5.19" - resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.19.tgz#e0a67e0e7017089fa0ee5eadd51a6da505b94cd4" - integrity sha512-mVngOPFYVVhec89rf/CiYQGTfaLRfHFtX+JQwY7sNYNqSA+gO8p4lNARe3Be6bJPgH+LUQuruIY9/ZDL6LT3HA== - dependencies: - "@react-aria/i18n" "^3.12.4" - "@react-aria/link" "^3.7.7" - "@react-aria/utils" "^3.26.0" - "@react-types/breadcrumbs" "^3.7.9" - "@react-types/shared" "^3.26.0" + version "3.5.27" + resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.27.tgz#594e6190518baa3da324a79e24a539e4a9606f6b" + integrity sha512-fuXD9nvBaBVZO0Z6EntBlxQD621/2Ldcxz76jFjc4V/jNOq/6BIVQRtpnAYYrSTiW3ZV2IoAyxRWNxQU22hOow== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/link" "^3.8.4" + "@react-aria/utils" "^3.30.0" + "@react-types/breadcrumbs" "^3.7.15" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/button@^3.10.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.11.0.tgz#cb7790db23949ec9c1e698fa531ee5471cf2b515" - integrity sha512-b37eIV6IW11KmNIAm65F3SEl2/mgj5BrHIysW6smZX3KoKWTGYsYfcQkmtNgY0GOSFfDxMCoolsZ6mxC00nSDA== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/interactions" "^3.22.5" - "@react-aria/toolbar" "3.0.0-beta.11" - "@react-aria/utils" "^3.26.0" - "@react-stately/toggle" "^3.8.0" - "@react-types/button" "^3.10.1" - "@react-types/shared" "^3.26.0" + version "3.14.0" + resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.14.0.tgz#3d0de54d9308812205c29e2294554a77bb8d6cea" + integrity sha512-we6z+2GpZO8lGD6EPmYH2S87kLCpU14D2E3tD2vES+SS2sZM2qcm2dUGpeo4+gZqBToLWKEBAGCSlkWEtgS19A== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/toolbar" "3.0.0-beta.19" + "@react-aria/utils" "^3.30.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/calendar@^3.5.12": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.6.0.tgz#d5e7cf4beb8724648a7042dbc5bb519de4351906" - integrity sha512-tZ3nd5DP8uxckbj83Pt+4RqgcTWDlGi7njzc7QqFOG2ApfnYDUXbIpb/Q4KY6JNlJskG8q33wo0XfOwNy8J+eg== - dependencies: - "@internationalized/date" "^3.6.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/live-announcer" "^3.4.1" - "@react-aria/utils" "^3.26.0" - "@react-stately/calendar" "^3.6.0" - "@react-types/button" "^3.10.1" - "@react-types/calendar" "^3.5.0" - "@react-types/shared" "^3.26.0" + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.9.0.tgz#6b5a80df82384e47ebcb8e8aed73ce706ff42efd" + integrity sha512-YxHLqL/LZrgwYGKzlQ96Fgt6gC+Q1L8k56sD51jJAtiD+YtT/pKJfK1zjZ3rtHtPTDYzosJ8vFgOmZNpnKQpXQ== + dependencies: + "@internationalized/date" "^3.8.2" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/calendar" "^3.8.3" + "@react-types/button" "^3.13.0" + "@react-types/calendar" "^3.7.3" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/checkbox@^3.14.7": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.15.0.tgz#4d224b71c65d6a079ff935ab22c806323f84b746" - integrity sha512-z/8xd4em7o0MroBXwkkwv7QRwiJaA1FwqMhRUb7iqtBGP2oSytBEDf0N7L09oci32a1P4ZPz2rMK5GlLh/PD6g== - dependencies: - "@react-aria/form" "^3.0.11" - "@react-aria/interactions" "^3.22.5" - "@react-aria/label" "^3.7.13" - "@react-aria/toggle" "^3.10.10" - "@react-aria/utils" "^3.26.0" - "@react-stately/checkbox" "^3.6.10" - "@react-stately/form" "^3.1.0" - "@react-stately/toggle" "^3.8.0" - "@react-types/checkbox" "^3.9.0" - "@react-types/shared" "^3.26.0" + version "3.16.0" + resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.16.0.tgz#775b3c0bde40bcfa8ab28439ba896088ba489d1b" + integrity sha512-XPaMz1/iVBG6EbJOPYlNtvr+q4f0axJeoIvyzWW3ciIdDSX/3jYuFg/sv/b3OQQl389cbQ/WUBQyWre/uXWVEg== + dependencies: + "@react-aria/form" "^3.1.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/toggle" "^3.12.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/checkbox" "^3.7.0" + "@react-stately/form" "^3.2.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/color@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.0.2.tgz#3abeb7e9fa9756e1823e513921e04dcaa47b25cc" - integrity sha512-dSM5qQRcR1gRGYCBw0IGRmc29gjfoht3cQleKb8MMNcgHYa2oi5VdCs2yKXmYFwwVC6uPtnlNy9S6e0spqdr+w== - dependencies: - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/numberfield" "^3.11.9" - "@react-aria/slider" "^3.7.14" - "@react-aria/spinbutton" "^3.6.10" - "@react-aria/textfield" "^3.15.0" - "@react-aria/utils" "^3.26.0" - "@react-aria/visually-hidden" "^3.8.18" - "@react-stately/color" "^3.8.1" - "@react-stately/form" "^3.1.0" - "@react-types/color" "^3.0.1" - "@react-types/shared" "^3.26.0" + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.1.0.tgz#d131deef07ef66881e1dad4ed9d4e4f41b5242bc" + integrity sha512-95qcCmz5Ss6o1Z4Z7X3pEEQxoUA83qGNQkpjOvobcHbNWKfhvOAsUzdBleOx2NpyBzY16OAnhWR7PJZwR4AqiA== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/numberfield" "^3.12.0" + "@react-aria/slider" "^3.8.0" + "@react-aria/spinbutton" "^3.6.17" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/color" "^3.9.0" + "@react-stately/form" "^3.2.0" + "@react-types/color" "^3.1.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/combobox@^3.10.4": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.11.0.tgz#9489aaad342d092bf1fe1c4c382f6714316ac1c4" - integrity sha512-s88YMmPkMO1WSoiH1KIyZDLJqUwvM2wHXXakj3cYw1tBHGo4rOUFq+JWQIbM5EDO4HOR4AUUqzIUd0NO7t3zyg== - dependencies: - "@react-aria/i18n" "^3.12.4" - "@react-aria/listbox" "^3.13.6" - "@react-aria/live-announcer" "^3.4.1" - "@react-aria/menu" "^3.16.0" - "@react-aria/overlays" "^3.24.0" - "@react-aria/selection" "^3.21.0" - "@react-aria/textfield" "^3.15.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/collections" "^3.12.0" - "@react-stately/combobox" "^3.10.1" - "@react-stately/form" "^3.1.0" - "@react-types/button" "^3.10.1" - "@react-types/combobox" "^3.13.1" - "@react-types/shared" "^3.26.0" + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.13.0.tgz#b89b26553ee0b63ff35c51b3e214c55d076a5bf4" + integrity sha512-eBa8aWcL3Ar/BvgSaqYDmNQP70LPZ7us2myM31QQt2YDRptqGHd44wzXCts9SaDVIeMVy+AEY2NkuxrVE6yNrw== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/listbox" "^3.14.7" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/menu" "^3.19.0" + "@react-aria/overlays" "^3.28.0" + "@react-aria/selection" "^3.25.0" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/combobox" "^3.11.0" + "@react-stately/form" "^3.2.0" + "@react-types/button" "^3.13.0" + "@react-types/combobox" "^3.13.7" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/datepicker@^3.11.3": - version "3.12.0" - resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.12.0.tgz#a82ff3ebd3ead20a00096d082c1e6be47bbd5886" - integrity sha512-VYNXioLfddIHpwQx211+rTYuunDmI7VHWBRetCpH3loIsVFuhFSRchTQpclAzxolO3g0vO7pMVj9VYt7Swp6kg== - dependencies: - "@internationalized/date" "^3.6.0" - "@internationalized/number" "^3.6.0" - "@internationalized/string" "^3.2.5" - "@react-aria/focus" "^3.19.0" - "@react-aria/form" "^3.0.11" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/label" "^3.7.13" - "@react-aria/spinbutton" "^3.6.10" - "@react-aria/utils" "^3.26.0" - "@react-stately/datepicker" "^3.11.0" - "@react-stately/form" "^3.1.0" - "@react-types/button" "^3.10.1" - "@react-types/calendar" "^3.5.0" - "@react-types/datepicker" "^3.9.0" - "@react-types/dialog" "^3.5.14" - "@react-types/shared" "^3.26.0" + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.15.0.tgz#b110e35189dad1fd6008c2a271bf03624a0959b3" + integrity sha512-AONeLj7sMKz4JmzCu4bhsqwcNFXCSWoaBhi4wOJO9+WYmxudn5mSI9ez8NMCVn+s5kcYpyvzrrAFf/DvQ4UDgw== + dependencies: + "@internationalized/date" "^3.8.2" + "@internationalized/number" "^3.6.4" + "@internationalized/string" "^3.2.7" + "@react-aria/focus" "^3.21.0" + "@react-aria/form" "^3.1.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/spinbutton" "^3.6.17" + "@react-aria/utils" "^3.30.0" + "@react-stately/datepicker" "^3.15.0" + "@react-stately/form" "^3.2.0" + "@react-types/button" "^3.13.0" + "@react-types/calendar" "^3.7.3" + "@react-types/datepicker" "^3.13.0" + "@react-types/dialog" "^3.5.20" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/dialog@^3.5.18": - version "3.5.20" - resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.20.tgz#6404d2c1bab1ea9ecce3ebc7adce64733ecea985" - integrity sha512-l0GZVLgeOd3kL3Yj8xQW7wN3gn9WW3RLd/SGI9t7ciTq+I/FhftjXCWzXLlOCCTLMf+gv7eazecECtmoWUaZWQ== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/overlays" "^3.24.0" - "@react-aria/utils" "^3.26.0" - "@react-types/dialog" "^3.5.14" - "@react-types/shared" "^3.26.0" + version "3.5.28" + resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.28.tgz#0cc8dcec8399d17baa65f4a325e65c3a93f0a5e1" + integrity sha512-S9dgdFBQc9LbhyBiHwGPSATwtvsIl6h+UnxDJ4oKBSse+wxdAyshbZv2tyO5RFbe3k73SAgU7yKocfg7YyRM0A== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/overlays" "^3.28.0" + "@react-aria/utils" "^3.30.0" + "@react-types/dialog" "^3.5.20" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/dnd@^3.7.3": - version "3.8.0" - resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.8.0.tgz#7e3bfa3f509efeb9a872686e65641a719684e95a" - integrity sha512-JiqHY3E9fDU5Kb4gN22cuK6QNlpMCGe6ngR/BV+Q8mLEsdoWcoUAYOtYXVNNTRvCdVbEWI87FUU+ThyPpoDhNQ== - dependencies: - "@internationalized/string" "^3.2.5" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/live-announcer" "^3.4.1" - "@react-aria/overlays" "^3.24.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/dnd" "^3.5.0" - "@react-types/button" "^3.10.1" - "@react-types/shared" "^3.26.0" + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.11.0.tgz#5f945ed7ad0bb5faf49d700d93c603049e112a64" + integrity sha512-jr47o7Fy55eYjSKWqRyuWKPnynpgC4cE9YXnYg5xa+1woRefIF2IyteOxgSHeX16+6ef2UDSsvC61T3gS6NWxQ== + dependencies: + "@internationalized/string" "^3.2.7" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/overlays" "^3.28.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/dnd" "^3.6.1" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/focus@^3.18.3", "@react-aria/focus@^3.19.0": - version "3.19.0" - resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.19.0.tgz#82b9a5b83f023b943a7970df3d059f49d61df05d" - integrity sha512-hPF9EXoUQeQl1Y21/rbV2H4FdUR2v+4/I0/vB+8U3bT1CJ+1AFj1hc/rqx2DqEwDlEwOHN+E4+mRahQmlybq0A== +"@react-aria/focus@^3.18.3", "@react-aria/focus@^3.21.0": + version "3.21.0" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.21.0.tgz#d5bc327bee25e981934ea0ddb1defbe020a84f6a" + integrity sha512-7NEGtTPsBy52EZ/ToVKCu0HSelE3kq9qeis+2eEq90XSuJOMaDHUQrA7RC2Y89tlEwQB31bud/kKRi9Qme1dkA== dependencies: - "@react-aria/interactions" "^3.22.5" - "@react-aria/utils" "^3.26.0" - "@react-types/shared" "^3.26.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/form@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.0.11.tgz#84511874e1fad5f981bae97ebd4d549923849455" - integrity sha512-oXzjTiwVuuWjZ8muU0hp3BrDH5qjVctLOF50mjPvqUbvXQTHhoDxWweyIXPQjGshaqBd2w4pWaE4A2rG2O/apw== +"@react-aria/form@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.1.0.tgz#78961c7884e561f1a389cd10d94a069fc4455e83" + integrity sha512-aDAOZafrn0V8e09mDAtCvc+JnpnkFM9X8cbI5+fdXsXAA+JxO+3uRRfnJHBlIL0iLc4C4OVWxBxWToV95pg1KA== dependencies: - "@react-aria/interactions" "^3.22.5" - "@react-aria/utils" "^3.26.0" - "@react-stately/form" "^3.1.0" - "@react-types/shared" "^3.26.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/form" "^3.2.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/grid@^3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.11.0.tgz#5ad6596745482e109b3b47f1fec7ce372f632707" - integrity sha512-lN5FpQgu2Rq0CzTPWmzRpq6QHcMmzsXYeClsgO3108uVp1/genBNAObYVTxGOKe/jb9q99trz8EtIn05O6KN1g== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/live-announcer" "^3.4.1" - "@react-aria/selection" "^3.21.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/collections" "^3.12.0" - "@react-stately/grid" "^3.10.0" - "@react-stately/selection" "^3.18.0" - "@react-types/checkbox" "^3.9.0" - "@react-types/grid" "^3.2.10" - "@react-types/shared" "^3.26.0" +"@react-aria/grid@^3.14.3": + version "3.14.3" + resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.14.3.tgz#660a54b78e3c0b75d5330752c21de8b2f69a1133" + integrity sha512-O4Ius5tJqKcMGfQT6IXD4MnEOeq6f/59nKmfCLTXMREFac/oxafqanUx3zrEVYbaqLOjEmONcd8S61ptQM6aPg== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/grid" "^3.11.4" + "@react-stately/selection" "^3.20.4" + "@react-types/checkbox" "^3.10.0" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/gridlist@^3.10.0", "@react-aria/gridlist@^3.9.4": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.10.0.tgz#adc2f9896a2759bb29cec428378c8ac85235a110" - integrity sha512-UcblfSZ7kJBrjg9mQ5VbnRevN81UiYB4NuL5PwIpBpridO7tnl4ew6+96PYU7Wj1chHhPS3x0b0zmuSVN7A0LA== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/grid" "^3.11.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/selection" "^3.21.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/collections" "^3.12.0" - "@react-stately/list" "^3.11.1" - "@react-stately/tree" "^3.8.6" - "@react-types/shared" "^3.26.0" +"@react-aria/gridlist@^3.13.3", "@react-aria/gridlist@^3.9.4": + version "3.13.3" + resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.13.3.tgz#b90ec98839ec5b631825c45e4cad021e941b2b6f" + integrity sha512-U2x/1MpdrAgK/vay2s2nVSko4WysajlMS+L8c18HE/ig2to+C8tCPWH2UuK4jTQWrK5x/PxTH+/yvtytljnIuQ== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/grid" "^3.14.3" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/list" "^3.12.4" + "@react-stately/tree" "^3.9.1" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/i18n@^3.12.3", "@react-aria/i18n@^3.12.4": - version "3.12.4" - resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.4.tgz#4520ce48a1b6ebe4aa470d72eba300e65de01814" - integrity sha512-j9+UL3q0Ls8MhXV9gtnKlyozq4aM95YywXqnmJtzT1rYeBx7w28hooqrWkCYLfqr4OIryv1KUnPiCSLwC2OC7w== - dependencies: - "@internationalized/date" "^3.6.0" - "@internationalized/message" "^3.1.6" - "@internationalized/number" "^3.6.0" - "@internationalized/string" "^3.2.5" - "@react-aria/ssr" "^3.9.7" - "@react-aria/utils" "^3.26.0" - "@react-types/shared" "^3.26.0" +"@react-aria/i18n@^3.12.11", "@react-aria/i18n@^3.12.3": + version "3.12.11" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.11.tgz#839b98baf8b298ccc76b98c5d3ba3a889f61baf7" + integrity sha512-1mxUinHbGJ6nJ/uSl62dl48vdZfWTBZePNF/wWQy98gR0qNFXLeusd7CsEmJT1971CR5i/WNYUo1ezNlIJnu6A== + dependencies: + "@internationalized/date" "^3.8.2" + "@internationalized/message" "^3.1.8" + "@internationalized/number" "^3.6.4" + "@internationalized/string" "^3.2.7" + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/interactions@^3.22.3", "@react-aria/interactions@^3.22.5": - version "3.22.5" - resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.22.5.tgz#9cd8c93b8b6988f1d315d3efb450119d1432bbb8" - integrity sha512-kMwiAD9E0TQp+XNnOs13yVJghiy8ET8L0cbkeuTgNI96sOAp/63EJ1FSrDf17iD8sdjt41LafwX/dKXW9nCcLQ== +"@react-aria/interactions@^3.22.3", "@react-aria/interactions@^3.25.4": + version "3.25.4" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.25.4.tgz#2f0e21e8187b7f0944b323f55696cae9accb39e0" + integrity sha512-HBQMxgUPHrW8V63u9uGgBymkMfj6vdWbB0GgUJY49K9mBKMsypcHeWkWM6+bF7kxRO728/IK8bWDV6whDbqjHg== dependencies: - "@react-aria/ssr" "^3.9.7" - "@react-aria/utils" "^3.26.0" - "@react-types/shared" "^3.26.0" + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.30.0" + "@react-stately/flags" "^3.1.2" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/label@^3.7.12", "@react-aria/label@^3.7.13": - version "3.7.13" - resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.13.tgz#9e7153a1ded878b5147d141effc3eb226f3c6c1f" - integrity sha512-brSAXZVTey5RG/Ex6mTrV/9IhGSQFU4Al34qmjEDho+Z2qT4oPwf8k7TRXWWqzOU0ugYxekYbsLd2zlN3XvWcg== +"@react-aria/label@^3.7.12", "@react-aria/label@^3.7.20": + version "3.7.20" + resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.20.tgz#3e2a6d887588166fd98fc66e6d3fc2ebeaa59d3a" + integrity sha512-Hw7OsC2GBnjptyW1lC1+SNoSIZA0eIh02QnNDr1XX2S+BPfn958NxoI7sJIstO/TUpQVNqdjEN/NI6+cyuJE6g== dependencies: - "@react-aria/utils" "^3.26.0" - "@react-types/shared" "^3.26.0" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/link@^3.7.5", "@react-aria/link@^3.7.7": - version "3.7.7" - resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.7.7.tgz#5879c75068b63d55353b3e96b4fda0fa8753d1ad" - integrity sha512-eVBRcHKhNSsATYWv5wRnZXRqPVcKAWWakyvfrYePIKpC3s4BaHZyTGYdefk8ZwZdEOuQZBqLMnjW80q1uhtkuA== +"@react-aria/link@^3.7.5", "@react-aria/link@^3.8.4": + version "3.8.4" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.8.4.tgz#43ca9c9d82b84e157f7b25048c61f9b87328e87a" + integrity sha512-7cPRGIo7x6ZZv1dhp2xGjqLR1snazSQgl7tThrBDL5E8f6Yr7SVpxOOK5/EBmfpFkhkmmXEO/Fgo/GPJdc6Vmw== dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/interactions" "^3.22.5" - "@react-aria/utils" "^3.26.0" - "@react-types/link" "^3.5.9" - "@react-types/shared" "^3.26.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-types/link" "^3.6.3" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/listbox@^3.13.4", "@react-aria/listbox@^3.13.6": - version "3.13.6" - resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.13.6.tgz#43ff24f4a6540a9952729833201460fa6ab081f7" - integrity sha512-6hEXEXIZVau9lgBZ4VVjFR3JnGU+fJaPmV3HP0UZ2ucUptfG0MZo24cn+ZQJsWiuaCfNFv5b8qribiv+BcO+Kg== - dependencies: - "@react-aria/interactions" "^3.22.5" - "@react-aria/label" "^3.7.13" - "@react-aria/selection" "^3.21.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/collections" "^3.12.0" - "@react-stately/list" "^3.11.1" - "@react-types/listbox" "^3.5.3" - "@react-types/shared" "^3.26.0" +"@react-aria/listbox@^3.13.4", "@react-aria/listbox@^3.14.7": + version "3.14.7" + resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.14.7.tgz#079d40dc29f2601d4ceb894a9de0715e55e9c70f" + integrity sha512-U5a+AIDblaeQTIA1MDFUaYIKoPwPNAuY7SwkuA5Z7ClDOeQJkiyExmAoKcUXwUkrLULQcbOPKr401q38IL3T7Q== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/list" "^3.12.4" + "@react-types/listbox" "^3.7.2" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/live-announcer@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.1.tgz#efedf706b23f6e1b526a3a35c14c202ac3e68487" - integrity sha512-4X2mcxgqLvvkqxv2l1n00jTzUxxe0kkLiapBGH1LHX/CxA1oQcHDqv8etJ2ZOwmS/MSBBiWnv3DwYHDOF6ubig== +"@react-aria/live-announcer@^3.4.4": + version "3.4.4" + resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.4.tgz#0e6533940222208b323b71d56ac8e115b2121e6a" + integrity sha512-PTTBIjNRnrdJOIRTDGNifY2d//kA7GUAwRFJNOEwSNG4FW+Bq9awqLiflw0JkpyB0VNIwou6lqKPHZVLsGWOXA== dependencies: "@swc/helpers" "^0.5.0" -"@react-aria/menu@^3.15.4", "@react-aria/menu@^3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.16.0.tgz#119e562806e9f8a39fd468ab790d788905c6df83" - integrity sha512-TNk+Vd3TbpBPUxEloAdHRTaRxf9JBK7YmkHYiq0Yj5Lc22KS0E2eTyhpPM9xJvEWN2TlC5TEvNfdyui2kYWFFQ== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/overlays" "^3.24.0" - "@react-aria/selection" "^3.21.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/collections" "^3.12.0" - "@react-stately/menu" "^3.9.0" - "@react-stately/selection" "^3.18.0" - "@react-stately/tree" "^3.8.6" - "@react-types/button" "^3.10.1" - "@react-types/menu" "^3.9.13" - "@react-types/shared" "^3.26.0" +"@react-aria/menu@^3.15.4", "@react-aria/menu@^3.19.0": + version "3.19.0" + resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.19.0.tgz#a53d5506545131fbfa4e6848eb7b4fdadec69947" + integrity sha512-VLUGbZedKJvK2OFWEpa86GPIaj9QcWox/R9JXmNk6nyrAz/V46OBQENdliV26PEdBZgzrVxGvmkjaH7ZsN/32Q== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/overlays" "^3.28.0" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/menu" "^3.9.6" + "@react-stately/selection" "^3.20.4" + "@react-stately/tree" "^3.9.1" + "@react-types/button" "^3.13.0" + "@react-types/menu" "^3.10.3" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/meter@^3.4.17": - version "3.4.18" - resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.18.tgz#ff3f85f32ea30285e7e73386a641efdcedd88205" - integrity sha512-tTX3LLlmDIHqrC42dkdf+upb1c4UbhlpZ52gqB64lZD4OD4HE+vMTwNSe+7MRKMLvcdKPWCRC35PnxIHZ15kfQ== + version "3.4.25" + resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.25.tgz#f0bb2b10ffd47155257a0a23a1ea0b9ad52e7828" + integrity sha512-6IqOnwuEt8z6UDy8Ru3ZZRZIUiELD0N3Wi/udMfR8gz4oznutvnRCMpRXkVVaVLYQfRglybu2/Lxfe+rq8WiRg== dependencies: - "@react-aria/progress" "^3.4.18" - "@react-types/meter" "^3.4.5" - "@react-types/shared" "^3.26.0" + "@react-aria/progress" "^3.4.25" + "@react-types/meter" "^3.4.11" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/numberfield@^3.11.7", "@react-aria/numberfield@^3.11.9": - version "3.11.9" - resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.11.9.tgz#175f801b18740534dca023cfd9ce0349eff940b0" - integrity sha512-3tiGPx2y4zyOV7PmdBASes99ZZsFTZAJTnU45Z+p1CW4131lw7y2ZhbojBl7U6DaXAJvi1z6zY6cq2UE9w5a0Q== - dependencies: - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/spinbutton" "^3.6.10" - "@react-aria/textfield" "^3.15.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/form" "^3.1.0" - "@react-stately/numberfield" "^3.9.8" - "@react-types/button" "^3.10.1" - "@react-types/numberfield" "^3.8.7" - "@react-types/shared" "^3.26.0" +"@react-aria/numberfield@^3.11.7", "@react-aria/numberfield@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.12.0.tgz#e17ae9212d230ecb96c698d544561d0355862754" + integrity sha512-JkgkjYsZ9lN5m3//X3buOKVrA/QJEeeXJ+5T5r6AmF29YdIhD1Plf5AEOWoRpZWQ25chH7FI/Orsf4h3/SLOpg== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/spinbutton" "^3.6.17" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/form" "^3.2.0" + "@react-stately/numberfield" "^3.10.0" + "@react-types/button" "^3.13.0" + "@react-types/numberfield" "^3.8.13" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/overlays@^3.23.3", "@react-aria/overlays@^3.24.0": - version "3.24.0" - resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.24.0.tgz#7f97cd12506961abfab3ae653822cea05d1cacd3" - integrity sha512-0kAXBsMNTc/a3M07tK9Cdt/ea8CxTAEJ223g8YgqImlmoBBYAL7dl5G01IOj67TM64uWPTmZrOklBchHWgEm3A== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/ssr" "^3.9.7" - "@react-aria/utils" "^3.26.0" - "@react-aria/visually-hidden" "^3.8.18" - "@react-stately/overlays" "^3.6.12" - "@react-types/button" "^3.10.1" - "@react-types/overlays" "^3.8.11" - "@react-types/shared" "^3.26.0" +"@react-aria/overlays@^3.23.3", "@react-aria/overlays@^3.28.0": + version "3.28.0" + resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.28.0.tgz#152d97b34b0ccab4fc53b1ae4bbf229c937ed6d6" + integrity sha512-qaHahAXTmxXULgg2/UfWEIwfgdKsn27XYryXAWWDu2CAZTcbI+5mGwYrQZSDWraM6v5PUUepzOVvm7hjTqiMFw== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/overlays" "^3.6.18" + "@react-types/button" "^3.13.0" + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/progress@^3.4.17", "@react-aria/progress@^3.4.18": - version "3.4.18" - resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.18.tgz#948859ce1b0e13d935da7d4cbe6812d451472fe4" - integrity sha512-FOLgJ9t9i1u3oAAimybJG6r7/soNPBnJfWo4Yr6MmaUv90qVGa1h6kiuM5m9H/bm5JobAebhdfHit9lFlgsCmg== +"@react-aria/progress@^3.4.17", "@react-aria/progress@^3.4.25": + version "3.4.25" + resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.25.tgz#ff33ee73bb3ac4f04a711b02c3b85710693379bb" + integrity sha512-KD9Gow+Ip6ZCBdsarR+Hby3c4d99I6L95Ruf7tbCh4ut9i9Dbr+x99OwhpAbT0g549cOyeIqxutPkT+JuzrRuA== dependencies: - "@react-aria/i18n" "^3.12.4" - "@react-aria/label" "^3.7.13" - "@react-aria/utils" "^3.26.0" - "@react-types/progress" "^3.5.8" - "@react-types/shared" "^3.26.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-types/progress" "^3.5.14" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/radio@^3.10.8": - version "3.10.10" - resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.10.10.tgz#18e2811fb3e72298414c880bd9405ea3f1d83f1f" - integrity sha512-NVdeOVrsrHgSfwL2jWCCXFsWZb+RMRZErj5vthHQW4nkHECGOzeX56VaLWTSvdoCPqi9wdIX8A6K9peeAIgxzA== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/form" "^3.0.11" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/label" "^3.7.13" - "@react-aria/utils" "^3.26.0" - "@react-stately/radio" "^3.10.9" - "@react-types/radio" "^3.8.5" - "@react-types/shared" "^3.26.0" + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.12.0.tgz#fc32e49b3c791b5c2100ab6911a075c67c2aa1e3" + integrity sha512-//0zZUuHtbm6uZR9+sNRNzVcQpjJKjZj57bDD0lMNj3NZp/Tkw+zXIFy6j1adv3JMe6iYkzEgaB7YRDD1Fe/ZA== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/form" "^3.1.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-stately/radio" "^3.11.0" + "@react-types/radio" "^3.9.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/searchfield@^3.7.9": - version "3.7.11" - resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.7.11.tgz#2be234280cc4fb58a316db6ba1f95ea34754c043" - integrity sha512-wFf6QxtBFfoxy0ANxI0+ftFEBGynVCY0+ce4H4Y9LpUTQsIKMp3sdc7LoUFORWw5Yee6Eid5cFPQX0Ymnk+ZJg== - dependencies: - "@react-aria/i18n" "^3.12.4" - "@react-aria/textfield" "^3.15.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/searchfield" "^3.5.8" - "@react-types/button" "^3.10.1" - "@react-types/searchfield" "^3.5.10" - "@react-types/shared" "^3.26.0" + version "3.8.7" + resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.8.7.tgz#f45c7ec2a1ac24f607d353c69f27ba3aa20ea45a" + integrity sha512-15jfALRyz5EAA5tvIELVfUlqTFdk8oG442OiS3Xq/jJij8uKRzwUdnL57EVTFYyg+VMLp/t5wX+obXYcRG+kdQ== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/textfield" "^3.18.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/searchfield" "^3.5.14" + "@react-types/button" "^3.13.0" + "@react-types/searchfield" "^3.6.4" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/select@^3.14.10": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.15.0.tgz#e0b955ed908039f734805e852b58dec4b159adc9" - integrity sha512-zgBOUNy81aJplfc3NKDJMv8HkXjBGzaFF3XDzNfW8vJ7nD9rcTRUN5SQ1XCEnKMv12B/Euk9zt6kd+tX0wk1vQ== - dependencies: - "@react-aria/form" "^3.0.11" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/label" "^3.7.13" - "@react-aria/listbox" "^3.13.6" - "@react-aria/menu" "^3.16.0" - "@react-aria/selection" "^3.21.0" - "@react-aria/utils" "^3.26.0" - "@react-aria/visually-hidden" "^3.8.18" - "@react-stately/select" "^3.6.9" - "@react-types/button" "^3.10.1" - "@react-types/select" "^3.9.8" - "@react-types/shared" "^3.26.0" + version "3.16.0" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.16.0.tgz#cc3343733514a3fc271b91f3916b3f598ece695c" + integrity sha512-UkiLSxMOKWW24qnhZdOObkFLpauvmu0T6wuPXbdQgwlis/UeLzDamPAWc6loRFJgHCpJftaaaWVQG3ks4NX7ew== + dependencies: + "@react-aria/form" "^3.1.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/listbox" "^3.14.7" + "@react-aria/menu" "^3.19.0" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/select" "^3.7.0" + "@react-types/button" "^3.13.0" + "@react-types/select" "^3.10.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/selection@^3.20.0", "@react-aria/selection@^3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.21.0.tgz#c5660e73a38db5e3e1cdc722e408b4489f5f589a" - integrity sha512-52JJ6hlPcM+gt0VV3DBmz6Kj1YAJr13TfutrKfGWcK36LvNCBm1j0N+TDqbdnlp8Nue6w0+5FIwZq44XPYiBGg== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/utils" "^3.26.0" - "@react-stately/selection" "^3.18.0" - "@react-types/shared" "^3.26.0" +"@react-aria/selection@^3.20.0", "@react-aria/selection@^3.25.0": + version "3.25.0" + resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.25.0.tgz#f284a4ad9820dd2c01bc69c8670c2032021136e0" + integrity sha512-Q3U0Ya0PTP/TR0a2g+7YEbFVLphiWthmEkHyvOx9HsKSjE8w9wXY3C14DZWKskB/BBrXKJuOWxBDa0xhC83S+A== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/selection" "^3.20.4" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/separator@^3.4.3": - version "3.4.4" - resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.4.tgz#7975177d256d8e864625d9823bf7a6de5a6b6460" - integrity sha512-dH+qt0Mdh0nhKXCHW6AR4DF8DKLUBP26QYWaoThPdBwIpypH/JVKowpPtWms1P4b36U6XzHXHnTTEn/ZVoCqNA== + version "3.4.11" + resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.11.tgz#ec63787ccc2f9d583098af35ba02e895cd2bfbe5" + integrity sha512-WwYEb7Wga4YQvlEwbzlVcVkfByullcORKtIe30pmh1YkTRRVJhbRPaE/mwcSMufbfjSYdtDavxmF+WY7Tdb9/A== dependencies: - "@react-aria/utils" "^3.26.0" - "@react-types/shared" "^3.26.0" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/slider@^3.7.12", "@react-aria/slider@^3.7.14": - version "3.7.14" - resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.7.14.tgz#25a362725d6cd71e9b86477362a36c847c73384e" - integrity sha512-7rOiKjLkEZ0j7mPMlwrqivc+K4OSfL14slaQp06GHRiJkhiWXh2/drPe15hgNq55HmBQBpA0umKMkJcqVgmXPA== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/label" "^3.7.13" - "@react-aria/utils" "^3.26.0" - "@react-stately/slider" "^3.6.0" - "@react-types/shared" "^3.26.0" - "@react-types/slider" "^3.7.7" +"@react-aria/slider@^3.7.12", "@react-aria/slider@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.8.0.tgz#9535c2782ab7a2fb6a5d0497caa77a572ae70b81" + integrity sha512-D7Sa7q21cV3gBid7frjoYw6924qYqNdJn2oai1BEemHSuwQatRlm1o2j+fnPTy9sYZfNOqXYnv5YjEn0o1T+Gw== + dependencies: + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-stately/slider" "^3.7.0" + "@react-types/shared" "^3.31.0" + "@react-types/slider" "^3.8.0" "@swc/helpers" "^0.5.0" -"@react-aria/spinbutton@^3.6.10": - version "3.6.10" - resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.10.tgz#72154873de807638e17570bd57e8491912b613b7" - integrity sha512-nhYEYk7xUNOZDaqiQ5w/nHH9ouqjJbabTWXH+KK7UR1oVGfo4z1wG94l8KWF3Z6SGGnBxzLJyTBguZ4g9aYTSg== +"@react-aria/spinbutton@^3.6.17": + version "3.6.17" + resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.17.tgz#5b1f79389e176519923515cb987587990287b005" + integrity sha512-gdGc3kkqpvFUd9XsrhPwQHMrG2TY0LVuGGgjvaZwF/ONm9FMz393ogCM0P484HsjU50hClO+yiRRgNjdwDIzPQ== dependencies: - "@react-aria/i18n" "^3.12.4" - "@react-aria/live-announcer" "^3.4.1" - "@react-aria/utils" "^3.26.0" - "@react-types/button" "^3.10.1" - "@react-types/shared" "^3.26.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.30.0" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/ssr@^3.9.6", "@react-aria/ssr@^3.9.7": - version "3.9.7" - resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.7.tgz#d89d129f7bbc5148657e6c952ac31c9353183770" - integrity sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg== +"@react-aria/ssr@^3.9.10", "@react-aria/ssr@^3.9.6": + version "3.9.10" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.10.tgz#7fdc09e811944ce0df1d7e713de1449abd7435e6" + integrity sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ== dependencies: "@swc/helpers" "^0.5.0" "@react-aria/switch@^3.6.8": - version "3.6.10" - resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.6.10.tgz#8fa5729bc4e76ac3df51389a8996873142daedb8" - integrity sha512-FtaI9WaEP1tAmra1sYlAkYXg9x75P5UtgY8pSbe9+1WRyWbuE1QZT+RNCTi3IU4fZ7iJQmXH6+VaMyzPlSUagw== - dependencies: - "@react-aria/toggle" "^3.10.10" - "@react-stately/toggle" "^3.8.0" - "@react-types/shared" "^3.26.0" - "@react-types/switch" "^3.5.7" + version "3.7.6" + resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.7.6.tgz#fe250201f17e7201ef3bb78a0979241506ebcea5" + integrity sha512-C+Od8hZNZCf3thgtZnZKzHl5b/63Q9xf+Pw6ugLA1qaKazwp46x1EwUVVqVhfAeVhmag++eHs8Lol5ZwQEinjQ== + dependencies: + "@react-aria/toggle" "^3.12.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/shared" "^3.31.0" + "@react-types/switch" "^3.5.13" "@swc/helpers" "^0.5.0" "@react-aria/table@^3.15.4": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.16.0.tgz#f0ffb51f52494e68f2c3b81fba44278fbdc48c28" - integrity sha512-9xF9S3CJ7XRiiK92hsIKxPedD0kgcQWwqTMtj3IBynpQ4vsnRiW3YNIzrn9C3apjknRZDTSta8O2QPYCUMmw2A== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/grid" "^3.11.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/live-announcer" "^3.4.1" - "@react-aria/utils" "^3.26.0" - "@react-aria/visually-hidden" "^3.8.18" - "@react-stately/collections" "^3.12.0" - "@react-stately/flags" "^3.0.5" - "@react-stately/table" "^3.13.0" - "@react-types/checkbox" "^3.9.0" - "@react-types/grid" "^3.2.10" - "@react-types/shared" "^3.26.0" - "@react-types/table" "^3.10.3" + version "3.17.6" + resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.17.6.tgz#dc2d645112434371cb50b1a9bcfbfb00f0a49a49" + integrity sha512-PSEaeKOIazVEaykeTLudPbDLytJgOPLZJalS/xXY0/KL+Gi0Olchmz4tvS0WBe87ChmlVi6GQqU+stk23aZVWg== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/grid" "^3.14.3" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.30.0" + "@react-aria/visually-hidden" "^3.8.26" + "@react-stately/collections" "^3.12.6" + "@react-stately/flags" "^3.1.2" + "@react-stately/table" "^3.14.4" + "@react-types/checkbox" "^3.10.0" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" + "@react-types/table" "^3.13.2" "@swc/helpers" "^0.5.0" "@react-aria/tabs@^3.9.6": - version "3.9.8" - resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.9.8.tgz#a0a647a4e2d1783125779473536419fd8caa9cfa" - integrity sha512-Nur/qRFBe+Zrt4xcCJV/ULXCS3Mlae+B89bp1Gl20vSDqk6uaPtGk+cS5k03eugOvas7AQapqNJsJgKd66TChw== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/selection" "^3.21.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/tabs" "^3.7.0" - "@react-types/shared" "^3.26.0" - "@react-types/tabs" "^3.3.11" + version "3.10.6" + resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.10.6.tgz#d2a78cd6b7bca78c60a01cb0e8b2b8230514f614" + integrity sha512-L8MaE7+bu6ByDOUxNPpMMYxdHULhKUfBoXdsSsXqb1z3QxdFW2zovfag0dvpyVWB6ALghX2T0PlTUNqaKA5tGw== + dependencies: + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/tabs" "^3.8.4" + "@react-types/shared" "^3.31.0" + "@react-types/tabs" "^3.3.17" "@swc/helpers" "^0.5.0" "@react-aria/tag@^3.4.6": - version "3.4.8" - resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.4.8.tgz#856899a53c2be2b8aea3d5aca020edf8608246b2" - integrity sha512-exWl52bsFtJuzaqMYvSnLteUoPqb3Wf+uICru/yRtREJsWVqjJF38NCVlU73Yqd9qMPTctDrboSZFAWAWKDxoA== - dependencies: - "@react-aria/gridlist" "^3.10.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/interactions" "^3.22.5" - "@react-aria/label" "^3.7.13" - "@react-aria/selection" "^3.21.0" - "@react-aria/utils" "^3.26.0" - "@react-stately/list" "^3.11.1" - "@react-types/button" "^3.10.1" - "@react-types/shared" "^3.26.0" + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.7.0.tgz#c34c97842607f0de5c936823e42945de2e6339dd" + integrity sha512-nU0Sl7u82RBn8XLNyrjkXhtw+xbJD9fyjesmDu7zeOq78e4eunKW7OZ/9+t+Lyu5wW+B7vKvetIgkdXKPQm3MA== + dependencies: + "@react-aria/gridlist" "^3.13.3" + "@react-aria/i18n" "^3.12.11" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/selection" "^3.25.0" + "@react-aria/utils" "^3.30.0" + "@react-stately/list" "^3.12.4" + "@react-types/button" "^3.13.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/textfield@^3.14.9", "@react-aria/textfield@^3.15.0": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.15.0.tgz#17ebac0b73f084622aaf9697576b82155bed67cb" - integrity sha512-V5mg7y1OR6WXYHdhhm4FC7QyGc9TideVRDFij1SdOJrIo5IFB7lvwpOS0GmgwkVbtr71PTRMjZnNbrJUFU6VNA== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/form" "^3.0.11" - "@react-aria/label" "^3.7.13" - "@react-aria/utils" "^3.26.0" - "@react-stately/form" "^3.1.0" - "@react-stately/utils" "^3.10.5" - "@react-types/shared" "^3.26.0" - "@react-types/textfield" "^3.10.0" +"@react-aria/textfield@^3.14.9", "@react-aria/textfield@^3.18.0": + version "3.18.0" + resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.18.0.tgz#fc5e4742559b53b8ec0a5037337743506a6c8071" + integrity sha512-kCwbyDHi2tRaD/OjagA3m3q2mMZUPeXY7hRqhDxpl2MwyIdd+/PQOJLM8tZr5+m2zvBx+ffOcjZMGTMwMtoV5w== + dependencies: + "@react-aria/form" "^3.1.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/label" "^3.7.20" + "@react-aria/utils" "^3.30.0" + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@react-types/textfield" "^3.12.4" "@swc/helpers" "^0.5.0" -"@react-aria/toggle@^3.10.10": - version "3.10.10" - resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.10.10.tgz#444658bf606e6d56b1fd96737d5a552c93493979" - integrity sha512-QwMT/vTNrbrILxWVHfd9zVQ3mV2NdBwyRu+DphVQiFAXcmc808LEaIX2n0lI6FCsUDC9ZejCyvzd91/YemdZ1Q== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/interactions" "^3.22.5" - "@react-aria/utils" "^3.26.0" - "@react-stately/toggle" "^3.8.0" - "@react-types/checkbox" "^3.9.0" - "@react-types/shared" "^3.26.0" +"@react-aria/toggle@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.12.0.tgz#93e4037be4f52b3b8cf5e4f1e087184cf1afda4b" + integrity sha512-JfcrF8xUEa2CbbUXp+WQiTBVwSM/dm21v5kueQlksvLfXG6DGE8/zjM6tJFErrFypAasc1JXyrI4dspLOWCfRA== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/toggle" "^3.9.0" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-aria/toolbar@3.0.0-beta.11": - version "3.0.0-beta.11" - resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.11.tgz#019c9ff2a47ad207504a95afeb0f863cf71a114b" - integrity sha512-LM3jTRFNDgoEpoL568WaiuqiVM7eynSQLJis1hV0vlVnhTd7M7kzt7zoOjzxVb5Uapz02uCp1Fsm4wQMz09qwQ== +"@react-aria/toolbar@3.0.0-beta.19": + version "3.0.0-beta.19" + resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.19.tgz#695b165ff0285be32e70b532e7d5b8e17da8dec1" + integrity sha512-G4sgtOUTUUJHznXlpKcY64SxD2gKOqIQXZXjWTVcY/Q5hAjl8gbTt5XIED22GmeIgd/tVl6+lddGj6ESze4vSg== dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/i18n" "^3.12.4" - "@react-aria/utils" "^3.26.0" - "@react-types/shared" "^3.26.0" + "@react-aria/focus" "^3.21.0" + "@react-aria/i18n" "^3.12.11" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-aria/tooltip@^3.7.8": - version "3.7.10" - resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.7.10.tgz#d710532e80337e50be818dfbf2cc54d0a9b8c592" - integrity sha512-Udi3XOnrF/SYIz72jw9bgB74MG/yCOzF5pozHj2FH2HiJlchYv/b6rHByV/77IZemdlkmL/uugrv/7raPLSlnw== - dependencies: - "@react-aria/focus" "^3.19.0" - "@react-aria/interactions" "^3.22.5" - "@react-aria/utils" "^3.26.0" - "@react-stately/tooltip" "^3.5.0" - "@react-types/shared" "^3.26.0" - "@react-types/tooltip" "^3.4.13" + version "3.8.6" + resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.8.6.tgz#35818591795e464647efe71e595f4f407d21837e" + integrity sha512-lW/PegiswGLlCP0CM4FH2kbIrEe4Li2SoklzIRh4nXZtiLIexswoE5/5af7PMtoMAl31or6fHZleVLzZD4VcfA== + dependencies: + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-stately/tooltip" "^3.5.6" + "@react-types/shared" "^3.31.0" + "@react-types/tooltip" "^3.4.19" "@swc/helpers" "^0.5.0" -"@react-aria/utils@^3.25.3", "@react-aria/utils@^3.26.0": - version "3.26.0" - resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.26.0.tgz#833cbfa33e75d15835b757791b3f754432d2f948" - integrity sha512-LkZouGSjjQ0rEqo4XJosS4L3YC/zzQkfRM3KoqK6fUOmUJ9t0jQ09WjiF+uOoG9u+p30AVg3TrZRUWmoTS+koQ== +"@react-aria/utils@^3.25.3", "@react-aria/utils@^3.30.0": + version "3.30.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.30.0.tgz#68aa1d703c9e0468350bd1e3b583d99e9e69795a" + integrity sha512-ydA6y5G1+gbem3Va2nczj/0G0W7/jUVo/cbN10WA5IizzWIwMP5qhFr7macgbKfHMkZ+YZC3oXnt2NNre5odKw== dependencies: - "@react-aria/ssr" "^3.9.7" - "@react-stately/utils" "^3.10.5" - "@react-types/shared" "^3.26.0" + "@react-aria/ssr" "^3.9.10" + "@react-stately/flags" "^3.1.2" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/visually-hidden@^3.8.16", "@react-aria/visually-hidden@^3.8.18": - version "3.8.18" - resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.18.tgz#13c168736944cbe19cd8917ec33a4e6f5f694119" - integrity sha512-l/0igp+uub/salP35SsNWq5mGmg3G5F5QMS1gDZ8p28n7CgjvzyiGhJbbca7Oxvaw1HRFzVl9ev+89I7moNnFQ== +"@react-aria/visually-hidden@^3.8.16", "@react-aria/visually-hidden@^3.8.26": + version "3.8.26" + resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.26.tgz#38d8432bc8609c33754ddeb5d279f54c473b2afd" + integrity sha512-Lz36lTVaQbv5Kn74sPv0l9SnLQ5XHKCoq2zilP14Eb4QixDIqR7Ovj43m+6wi9pynf29jtOb/8D/9jrTjbmmgw== dependencies: - "@react-aria/interactions" "^3.22.5" - "@react-aria/utils" "^3.26.0" - "@react-types/shared" "^3.26.0" + "@react-aria/interactions" "^3.25.4" + "@react-aria/utils" "^3.30.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-oauth/google@^0.12.1": - version "0.12.1" - resolved "https://registry.yarnpkg.com/@react-oauth/google/-/google-0.12.1.tgz#b76432c3a525e9afe076f787d2ded003fcc1bee9" - integrity sha512-qagsy22t+7UdkYAiT5ZhfM4StXi9PPNvw0zuwNmabrWyMKddczMtBIOARflbaIj+wHiQjnMAsZmzsUYuXeyoSg== - -"@react-stately/calendar@^3.5.5", "@react-stately/calendar@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.6.0.tgz#c770890160c33826206a015eb7da32fe8ece81d5" - integrity sha512-GqUtOtGnwWjtNrJud8nY/ywI4VBP5byToNVRTnxbMl+gYO1Qe/uc5NG7zjwMxhb2kqSBHZFdkF0DXVqG2Ul+BA== - dependencies: - "@internationalized/date" "^3.6.0" - "@react-stately/utils" "^3.10.5" - "@react-types/calendar" "^3.5.0" - "@react-types/shared" "^3.26.0" + version "0.12.2" + resolved "https://registry.yarnpkg.com/@react-oauth/google/-/google-0.12.2.tgz#082086fcfac1309e4e66413e7a30d24f452445e9" + integrity sha512-d1GVm2uD4E44EJft2RbKtp8Z1fp/gK8Lb6KHgs3pHlM0PxCXGLaq8LLYQYENnN4xPWO1gkL4apBtlPKzpLvZwg== + +"@react-stately/calendar@^3.5.5", "@react-stately/calendar@^3.8.3": + version "3.8.3" + resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.8.3.tgz#749d8965d3825fdffd4b728b69fbd4c5099e667d" + integrity sha512-HTWD6ZKQcXDlvj6glEEG0oi2Tpkaw19y5rK526s04zJs894wFqM9PK0WHthEYqjCeQJ5B/OkyG19XX4lENxnZw== + dependencies: + "@internationalized/date" "^3.8.2" + "@react-stately/utils" "^3.10.8" + "@react-types/calendar" "^3.7.3" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/checkbox@^3.6.10", "@react-stately/checkbox@^3.6.9": - version "3.6.10" - resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.6.10.tgz#69b619fdfcf1e15d2d93392e13289a36d85a8a6c" - integrity sha512-LHm7i4YI8A/RdgWAuADrnSAYIaYYpQeZqsp1a03Og0pJHAlZL0ymN3y2IFwbZueY0rnfM+yF+kWNXjJqbKrFEQ== +"@react-stately/checkbox@^3.6.9", "@react-stately/checkbox@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.7.0.tgz#4464adc16148885a3a8e7fbdfb94eace75ee5887" + integrity sha512-opViVhNvxFVHjXhM4nA/E03uvbLazsIKloXX9JtyBCZAQRUag17dpmkekfIkHvP4o7z7AWFoibD8JBFV1IrMcQ== dependencies: - "@react-stately/form" "^3.1.0" - "@react-stately/utils" "^3.10.5" - "@react-types/checkbox" "^3.9.0" - "@react-types/shared" "^3.26.0" + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/collections@^3.11.0", "@react-stately/collections@^3.12.0": - version "3.12.0" - resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.12.0.tgz#6240d3517d0d86f7d9eb4997108fb432d569e8d7" - integrity sha512-MfR9hwCxe5oXv4qrLUnjidwM50U35EFmInUeFf8i9mskYwWlRYS0O1/9PZ0oF1M0cKambaRHKEy98jczgb9ycA== +"@react-stately/collections@^3.11.0", "@react-stately/collections@^3.12.6": + version "3.12.6" + resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.12.6.tgz#0d8b6d2744dd0c29d31842d39a112d30c27a4387" + integrity sha512-S158RKWGZSodbJXKZDdcnrLzFxzFmyRWDNakQd1nBGhSrW2JV8lDn9ku5Og7TrjoEpkz//B2oId648YT792ilw== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/color@^3.8.0", "@react-stately/color@^3.8.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.8.1.tgz#13969f61f1c1b468fd891cc94582056fc2da9b9b" - integrity sha512-7eN7K+KJRu+rxK351eGrzoq2cG+yipr90i5b1cUu4lioYmcH4WdsfjmM5Ku6gypbafH+kTDfflvO6hiY1NZH+A== - dependencies: - "@internationalized/number" "^3.6.0" - "@internationalized/string" "^3.2.5" - "@react-aria/i18n" "^3.12.4" - "@react-stately/form" "^3.1.0" - "@react-stately/numberfield" "^3.9.8" - "@react-stately/slider" "^3.6.0" - "@react-stately/utils" "^3.10.5" - "@react-types/color" "^3.0.1" - "@react-types/shared" "^3.26.0" +"@react-stately/color@^3.8.0", "@react-stately/color@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.9.0.tgz#9233c4d04d1794d0cb34b5687bca5edca7e7f1e6" + integrity sha512-9eG0gDxVIu+A+DTdfwyYuU4pR788pVdq1Snpk8el787OsOb5WiuT4C4VWJb5Qbrq2PiFhhZmxuJXpzz4B1gW3A== + dependencies: + "@internationalized/number" "^3.6.4" + "@internationalized/string" "^3.2.7" + "@react-stately/form" "^3.2.0" + "@react-stately/numberfield" "^3.10.0" + "@react-stately/slider" "^3.7.0" + "@react-stately/utils" "^3.10.8" + "@react-types/color" "^3.1.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/combobox@^3.10.0", "@react-stately/combobox@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.10.1.tgz#ebae28c5341d06d69cc8e50055fa816dee19522b" - integrity sha512-Rso+H+ZEDGFAhpKWbnRxRR/r7YNmYVtt+Rn0eNDNIUp3bYaxIBCdCySyAtALs4I8RZXZQ9zoUznP7YeVwG3cLg== - dependencies: - "@react-stately/collections" "^3.12.0" - "@react-stately/form" "^3.1.0" - "@react-stately/list" "^3.11.1" - "@react-stately/overlays" "^3.6.12" - "@react-stately/select" "^3.6.9" - "@react-stately/utils" "^3.10.5" - "@react-types/combobox" "^3.13.1" - "@react-types/shared" "^3.26.0" +"@react-stately/combobox@^3.10.0", "@react-stately/combobox@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.11.0.tgz#c8e647bedf747c14c6c91b136a0dc551d20a22a5" + integrity sha512-W9COXdSOC+uqCZrRHJI0K7emlPb/Tx4A89JHWBcFmiAk+hs1Cnlyjw3aaqEiT8A8/HxDNMO9QcfisWC1iNyE9A== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/form" "^3.2.0" + "@react-stately/list" "^3.12.4" + "@react-stately/overlays" "^3.6.18" + "@react-stately/select" "^3.7.0" + "@react-stately/utils" "^3.10.8" + "@react-types/combobox" "^3.13.7" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" "@react-stately/data@^3.11.7": - version "3.12.0" - resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.12.0.tgz#4f0fd89be2fa64ca7c0ad92d8cf20f2cba961fc0" - integrity sha512-6PiW2oA56lcH1CVjDcajutzsv91w/PER8K61/OGxtNFFUWaIZH80RWmK4kjU/Lf0vygzXCxout3kEb388lUk0w== + version "3.13.2" + resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.13.2.tgz#b649aa85c58e0e20e257fc749daa8042b7d482fb" + integrity sha512-xdCqR8dJ3cnvO8EdCeuQ335dOuBqEV4z/3LnpxmR11gyn8dWwtY5O794g5+AS0KqCgd9W0v7iBrRywq5UT2pCA== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/datepicker@^3.10.3", "@react-stately/datepicker@^3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.11.0.tgz#5f4daff449f756dc40b4201ae337dd4a3f29facc" - integrity sha512-d9MJF34A0VrhL5y5S8mAISA8uwfNCQKmR2k4KoQJm3De1J8SQeNzSjLviAwh1faDow6FXGlA6tVbTrHyDcBgBg== - dependencies: - "@internationalized/date" "^3.6.0" - "@internationalized/string" "^3.2.5" - "@react-stately/form" "^3.1.0" - "@react-stately/overlays" "^3.6.12" - "@react-stately/utils" "^3.10.5" - "@react-types/datepicker" "^3.9.0" - "@react-types/shared" "^3.26.0" +"@react-stately/datepicker@^3.10.3", "@react-stately/datepicker@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.15.0.tgz#a152219bb362d2d81169e6ef4a12df988f93efe8" + integrity sha512-OuBx+h802CoANy6KNR6XuZCndiyRf9vpB32CYZX86nqWy21GSTeT73G41ze5cAH88A/6zmtpYK24nTlk8bdfWA== + dependencies: + "@internationalized/date" "^3.8.2" + "@internationalized/string" "^3.2.7" + "@react-stately/form" "^3.2.0" + "@react-stately/overlays" "^3.6.18" + "@react-stately/utils" "^3.10.8" + "@react-types/datepicker" "^3.13.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/dnd@^3.4.3", "@react-stately/dnd@^3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.5.0.tgz#3061233709f7113f6492de33204aea507c243a2e" - integrity sha512-ZcWFw1npEDnATiy3TEdzA1skQ3UEIyfbNA6VhPNO8yiSVLxoxBOaEaq8VVS72fRGAtxud6dgOy8BnsP9JwDClQ== +"@react-stately/dnd@^3.4.3", "@react-stately/dnd@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.6.1.tgz#409ba99b653cf7cdd140f8e582f11d911114178e" + integrity sha512-cbBLptL+tpXFQ0oU0v6GBtSvzP0doohyhCIr8pOzk6aYutFI0c5JZw8LGoKN/GLfXkm7iPyrfCKeKqDlDTHCzQ== dependencies: - "@react-stately/selection" "^3.18.0" - "@react-types/shared" "^3.26.0" + "@react-stately/selection" "^3.20.4" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/flags@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.0.5.tgz#b35bcbd3b80c4f821e23e9c649566a4af11e97bf" - integrity sha512-6wks4csxUwPCp23LgJSnkBRhrWpd9jGd64DjcCTNB2AHIFu7Ab1W59pJpUL6TW7uAxVxdNKjgn6D1hlBy8qWsA== +"@react-stately/flags@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.1.2.tgz#5c8e5ae416d37d37e2e583d2fcb3a046293504f2" + integrity sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg== dependencies: "@swc/helpers" "^0.5.0" -"@react-stately/form@^3.0.6", "@react-stately/form@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.1.0.tgz#7fdb4ca153be18e7516a02e507ada393ad38945d" - integrity sha512-E2wxNQ0QaTyDHD0nJFtTSnEH9A3bpJurwxhS4vgcUmESHgjFEMLlC9irUSZKgvOgb42GAq+fHoWBsgKeTp9Big== +"@react-stately/form@^3.0.6", "@react-stately/form@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.2.0.tgz#77b4030a9100a50f3e322c277783a4c0740948f1" + integrity sha512-PfefxvT7/BIhAGpD4oQpdcxnL8cfN0ZTQxQq+Wmb9z3YzK1oM8GFxb8eGdDRG71JeF8WUNMAQVZFhgl00Z/YKg== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/grid@^3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.10.0.tgz#d74e46f85a662092c61812a8508cf4ac8721ec6d" - integrity sha512-ii+DdsOBvCnHMgL0JvUfFwO1kiAPP19Bpdpl6zn/oOltk6F5TmnoyNrzyz+2///1hCiySI3FE1O7ujsAQs7a6Q== +"@react-stately/grid@^3.11.4": + version "3.11.4" + resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.11.4.tgz#ec5eac6a8641d175ebef0f57c666af2cb18dad1f" + integrity sha512-oaXFSk2eM0PJ0GVniGA0ZlTpAA0AL0O4MQ7V3cHqZAQbwSO0n2pT31GM0bSVnYP/qTF5lQHo3ECmRQCz0fVyMw== dependencies: - "@react-stately/collections" "^3.12.0" - "@react-stately/selection" "^3.18.0" - "@react-types/grid" "^3.2.10" - "@react-types/shared" "^3.26.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/selection" "^3.20.4" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/list@^3.11.0", "@react-stately/list@^3.11.1": - version "3.11.1" - resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.11.1.tgz#d1493e5b9c5cac6cafb3cb3a6edb852bf3cb208f" - integrity sha512-UCOpIvqBOjwLtk7zVTYWuKU1m1Oe61Q5lNar/GwHaV1nAiSQ8/yYlhr40NkBEs9X3plEfsV28UIpzOrYnu1tPg== +"@react-stately/list@^3.11.0", "@react-stately/list@^3.12.4": + version "3.12.4" + resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.12.4.tgz#0515247773f1e8c314137c2883f7d95eeb2a7957" + integrity sha512-r7vMM//tpmagyNlRzl2NFPPtx+az5R9pM6q7aI4aBf6/zpZt2eX2UW5gaDTGlkQng7r6OGyAgJD52jmGcCJk7Q== dependencies: - "@react-stately/collections" "^3.12.0" - "@react-stately/selection" "^3.18.0" - "@react-stately/utils" "^3.10.5" - "@react-types/shared" "^3.26.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/selection" "^3.20.4" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/menu@^3.8.3", "@react-stately/menu@^3.9.0": - version "3.9.0" - resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.9.0.tgz#b1e55996405f4e43ff844cbd325df9842914efe4" - integrity sha512-++sm0fzZeUs9GvtRbj5RwrP+KL9KPANp9f4SvtI3s+MP+Y/X3X7LNNePeeccGeyikB5fzMsuyvd82bRRW9IhDQ== +"@react-stately/menu@^3.8.3", "@react-stately/menu@^3.9.6": + version "3.9.6" + resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.9.6.tgz#5f478f2e2f4dedce30e935f95eae0251b5790e3f" + integrity sha512-2rVtgeVAiyr7qL8BhmCK/4el49rna/5kADRH5NfPdpXw8ZzaiiHq2RtX443Txj7pUU82CJWQn+CRobq7k6ZTEw== dependencies: - "@react-stately/overlays" "^3.6.12" - "@react-types/menu" "^3.9.13" - "@react-types/shared" "^3.26.0" + "@react-stately/overlays" "^3.6.18" + "@react-types/menu" "^3.10.3" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/numberfield@^3.9.7", "@react-stately/numberfield@^3.9.8": - version "3.9.8" - resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.9.8.tgz#863a6c0f7a4249759dd0c586f2e27dd2548aadee" - integrity sha512-J6qGILxDNEtu7yvd3/y+FpbrxEaAeIODwlrFo6z1kvuDlLAm/KszXAc75yoDi0OtakFTCMP6/HR5VnHaQdMJ3w== +"@react-stately/numberfield@^3.10.0", "@react-stately/numberfield@^3.9.7": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.10.0.tgz#f6b54e308ec0a9dca51892d1b670b56bbf88e435" + integrity sha512-6C8ML4/e2tcn01BRNfFLxetVaWwz0n0pVROnVpo8p761c6lmTqohqEMNcXCVNw9H0wsa1hug2a1S5PcN2OXgag== dependencies: - "@internationalized/number" "^3.6.0" - "@react-stately/form" "^3.1.0" - "@react-stately/utils" "^3.10.5" - "@react-types/numberfield" "^3.8.7" + "@internationalized/number" "^3.6.4" + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/numberfield" "^3.8.13" "@swc/helpers" "^0.5.0" -"@react-stately/overlays@^3.6.11", "@react-stately/overlays@^3.6.12": - version "3.6.12" - resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.12.tgz#beb594a0e140dbd7957bfa181006854f91480bea" - integrity sha512-QinvZhwZgj8obUyPIcyURSCjTZlqZYRRCS60TF8jH8ZpT0tEAuDb3wvhhSXuYA3Xo9EHLwvLjEf3tQKKdAQArw== +"@react-stately/overlays@^3.6.11", "@react-stately/overlays@^3.6.18": + version "3.6.18" + resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.18.tgz#d2a4f013c84e0e93654afc26bbaeac67f28e9f8f" + integrity sha512-g8n2FtDCxIg2wQ09R7lrM2niuxMPCdP17bxsPV9hyYnN6m42aAKGOhzWrFOK+3phQKgk/E1JQZEvKw1cyyGo1A== dependencies: - "@react-stately/utils" "^3.10.5" - "@react-types/overlays" "^3.8.11" + "@react-stately/utils" "^3.10.8" + "@react-types/overlays" "^3.9.0" "@swc/helpers" "^0.5.0" -"@react-stately/radio@^3.10.8", "@react-stately/radio@^3.10.9": - version "3.10.9" - resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.10.9.tgz#cf74b8f47cbef56836424d2e7d06c01fe9d9ea05" - integrity sha512-kUQ7VdqFke8SDRCatw2jW3rgzMWbvw+n2imN2THETynI47NmNLzNP11dlGO2OllRtTrsLhmBNlYHa3W62pFpAw== +"@react-stately/radio@^3.10.8", "@react-stately/radio@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.11.0.tgz#42130406a5d27ca021ddb95ff12e3530315718fe" + integrity sha512-hsCmKb9e/ygmzBADFYIGpEQ43LrxjWnlKESgxphvlv0Klla4d6XLAYSFOTX1kcjSztpvVWrdl4cIfmKVF1pz2g== dependencies: - "@react-stately/form" "^3.1.0" - "@react-stately/utils" "^3.10.5" - "@react-types/radio" "^3.8.5" - "@react-types/shared" "^3.26.0" + "@react-stately/form" "^3.2.0" + "@react-stately/utils" "^3.10.8" + "@react-types/radio" "^3.9.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/searchfield@^3.5.7", "@react-stately/searchfield@^3.5.8": - version "3.5.8" - resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.8.tgz#b927e25afd32b1a32f22d54df6d7b4968cb4cf33" - integrity sha512-jtquvGadx1DmtQqPKaVO6Qg/xpBjNxsOd59ciig9xRxpxV+90i996EX1E2R6R+tGJdSM1pD++7PVOO4yE++HOg== +"@react-stately/searchfield@^3.5.14", "@react-stately/searchfield@^3.5.7": + version "3.5.14" + resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.14.tgz#2887cd04bbd7c6e11087b71e75c3affbefc7f1bf" + integrity sha512-OAycTULyF/UWy7Odyzw5lZV2yWH+Cy7fWsZxDUedeUs4Aiwbb6D4ph9pGb0RvhD4S3+B490a2ijGgfsaDeorMA== dependencies: - "@react-stately/utils" "^3.10.5" - "@react-types/searchfield" "^3.5.10" + "@react-stately/utils" "^3.10.8" + "@react-types/searchfield" "^3.6.4" "@swc/helpers" "^0.5.0" -"@react-stately/select@^3.6.8", "@react-stately/select@^3.6.9": - version "3.6.9" - resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.6.9.tgz#088bb0fe7b16cc67d833f17c330df63c4310a5da" - integrity sha512-vASUDv7FhEYQURzM+JIwcusPv7/x/l3zHc/oKJPvoCl3aa9pwS8hZwS82SC00o2iFnrDscfDJju4IE/cd4hucg== - dependencies: - "@react-stately/form" "^3.1.0" - "@react-stately/list" "^3.11.1" - "@react-stately/overlays" "^3.6.12" - "@react-types/select" "^3.9.8" - "@react-types/shared" "^3.26.0" +"@react-stately/select@^3.6.8", "@react-stately/select@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.7.0.tgz#0fec2feeb6d52898590e7a8cf024650e13889f13" + integrity sha512-OWLOCKBEj8/XI+vzBSSHQAJu0Hf9Xl/flMhYh47f2b45bO++DRLcVsi8nycPNisudvK6xMQ8a/h4FwjePrCXfg== + dependencies: + "@react-stately/form" "^3.2.0" + "@react-stately/list" "^3.12.4" + "@react-stately/overlays" "^3.6.18" + "@react-types/select" "^3.10.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/selection@^3.17.0", "@react-stately/selection@^3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.18.0.tgz#eb723dc26eafd9b016c55056fb550bdde8b4f87b" - integrity sha512-6EaNNP3exxBhW2LkcRR4a3pg+3oDguZlBSqIVVR7lyahv/D8xXHRC4dX+m0mgGHJpsgjs7664Xx6c8v193TFxg== +"@react-stately/selection@^3.17.0", "@react-stately/selection@^3.20.4": + version "3.20.4" + resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.20.4.tgz#3bebfd5c6d4d27757531094a645dc8a3fa807f1b" + integrity sha512-Hxmc6NtECStYo+Z2uBRhQ80KPhbSF7xXv9eb4qN8dhyuSnsD6c0wc6oAJsv18dldcFz8VrD48aP/uff9mj0hxQ== dependencies: - "@react-stately/collections" "^3.12.0" - "@react-stately/utils" "^3.10.5" - "@react-types/shared" "^3.26.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/slider@^3.5.8", "@react-stately/slider@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.6.0.tgz#20439e08915725c4f6ba2285a561ae92fe59d997" - integrity sha512-w5vJxVh267pmD1X+Ppd9S3ZzV1hcg0cV8q5P4Egr160b9WMcWlUspZPtsthwUlN7qQe/C8y5IAhtde4s29eNag== +"@react-stately/slider@^3.5.8", "@react-stately/slider@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.7.0.tgz#64a5b3f3aa5ad961c45f18de12ed46eda9235716" + integrity sha512-quxqkyyxrxLELYEkPrIrucpVPdYDK8yyliv/vvNuHrjuLRIvx6UmssxqESp2EpZfwPYtEB29QXbAKT9+KuXoCQ== dependencies: - "@react-stately/utils" "^3.10.5" - "@react-types/shared" "^3.26.0" - "@react-types/slider" "^3.7.7" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" + "@react-types/slider" "^3.8.0" "@swc/helpers" "^0.5.0" -"@react-stately/table@^3.12.3", "@react-stately/table@^3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.13.0.tgz#8465030f568b5ee779623d99b2ef22940a99a6cd" - integrity sha512-mRbNYrwQIE7xzVs09Lk3kPteEVFVyOc20vA8ph6EP54PiUf/RllJpxZe/WUYLf4eom9lUkRYej5sffuUBpxjCA== - dependencies: - "@react-stately/collections" "^3.12.0" - "@react-stately/flags" "^3.0.5" - "@react-stately/grid" "^3.10.0" - "@react-stately/selection" "^3.18.0" - "@react-stately/utils" "^3.10.5" - "@react-types/grid" "^3.2.10" - "@react-types/shared" "^3.26.0" - "@react-types/table" "^3.10.3" +"@react-stately/table@^3.12.3", "@react-stately/table@^3.14.4": + version "3.14.4" + resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.14.4.tgz#d12eb43bcdcebc0f6b07e26abc19f3330b8dd31a" + integrity sha512-uhwk8z3DemozD+yHBjSa4WyxKczpDkxhJhW7ZVOY+1jNuTYxc9/JxzPsHICrlDVV8EPWwwyMUz8eO/8rKN7DbA== + dependencies: + "@react-stately/collections" "^3.12.6" + "@react-stately/flags" "^3.1.2" + "@react-stately/grid" "^3.11.4" + "@react-stately/selection" "^3.20.4" + "@react-stately/utils" "^3.10.8" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" + "@react-types/table" "^3.13.2" "@swc/helpers" "^0.5.0" -"@react-stately/tabs@^3.6.10", "@react-stately/tabs@^3.7.0": - version "3.7.0" - resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.7.0.tgz#f849b334c5e7d39a37c2e9ffa3114531bf8ce6e4" - integrity sha512-ox4hTkfZCoR4Oyr3Op3rBlWNq2Wxie04vhEYpTZQ2hobR3l4fYaOkd7CPClILktJ3TC104j8wcb0knWxIBRx9w== +"@react-stately/tabs@^3.6.10", "@react-stately/tabs@^3.8.4": + version "3.8.4" + resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.8.4.tgz#c9bd860ed98320502eda48e60a8c603f35f0f213" + integrity sha512-2Tr4yXkcNDLyyxrZr+c4FnAW/wkSim3UhDUWoOgTCy3mwlQzdh9r5qJrOZRghn1QvF7p8Ahp7O7qxwd2ZGJrvQ== dependencies: - "@react-stately/list" "^3.11.1" - "@react-types/shared" "^3.26.0" - "@react-types/tabs" "^3.3.11" + "@react-stately/list" "^3.12.4" + "@react-types/shared" "^3.31.0" + "@react-types/tabs" "^3.3.17" "@swc/helpers" "^0.5.0" -"@react-stately/toggle@^3.7.8", "@react-stately/toggle@^3.8.0": - version "3.8.0" - resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.8.0.tgz#39a3e45989f56e236809d8fe69c160cc88a616f5" - integrity sha512-pyt/k/J8BwE/2g6LL6Z6sMSWRx9HEJB83Sm/MtovXnI66sxJ2EfQ1OaXB7Su5PEL9OMdoQF6Mb+N1RcW3zAoPw== +"@react-stately/toggle@^3.7.8", "@react-stately/toggle@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.9.0.tgz#f32db5d0ad5cb382add52a77a9025ce3fdf10fd8" + integrity sha512-1URd97R5nbFF9Hc1nQBhvln55EnOkLNz6pjtXU7TCnV4tYVbe+tc++hgr5XRt6KAfmuXxVDujlzRc6QjfCn0cQ== dependencies: - "@react-stately/utils" "^3.10.5" - "@react-types/checkbox" "^3.9.0" - "@react-types/shared" "^3.26.0" + "@react-stately/utils" "^3.10.8" + "@react-types/checkbox" "^3.10.0" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/tooltip@^3.4.13", "@react-stately/tooltip@^3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.5.0.tgz#1016952eb4427d5b848e2efcb24eee47e2a26b59" - integrity sha512-+xzPNztJDd2XJD0X3DgWKlrgOhMqZpSzsIssXeJgO7uCnP8/Z513ESaipJhJCFC8fxj5caO/DK4Uu8hEtlB8cQ== +"@react-stately/tooltip@^3.4.13", "@react-stately/tooltip@^3.5.6": + version "3.5.6" + resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.5.6.tgz#cb0c23f089a5ba740132b33a2148c92c1567a449" + integrity sha512-BnOtE7726t1sCKPGbwzzEtEx40tjpbJvw5yqpoVnAV0OLfrXtLVYfd7tWRHmZOYmhELaUnY+gm3ZFYtwvnjs+A== dependencies: - "@react-stately/overlays" "^3.6.12" - "@react-types/tooltip" "^3.4.13" + "@react-stately/overlays" "^3.6.18" + "@react-types/tooltip" "^3.4.19" "@swc/helpers" "^0.5.0" -"@react-stately/tree@^3.8.5", "@react-stately/tree@^3.8.6": - version "3.8.6" - resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.8.6.tgz#85dc33c5d5b9a455ffc0b474300957e511db1ea4" - integrity sha512-lblUaxf1uAuIz5jm6PYtcJ+rXNNVkqyFWTIMx6g6gW/mYvm8GNx1G/0MLZE7E6CuDGaO9dkLSY2bB1uqyKHidA== +"@react-stately/tree@^3.8.5", "@react-stately/tree@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.9.1.tgz#17498b0832338f9aba82aebcb9e359df8b7680fc" + integrity sha512-dyoPIvPK/cs03Tg/MQSODi2kKYW1zaiOG9KC2P0c8b44mywU2ojBKzhSJky3dBkJ4VVGy7L+voBh50ELMjEa8Q== dependencies: - "@react-stately/collections" "^3.12.0" - "@react-stately/selection" "^3.18.0" - "@react-stately/utils" "^3.10.5" - "@react-types/shared" "^3.26.0" + "@react-stately/collections" "^3.12.6" + "@react-stately/selection" "^3.20.4" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.31.0" "@swc/helpers" "^0.5.0" -"@react-stately/utils@^3.10.5": - version "3.10.5" - resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.5.tgz#47bb91cd5afd1bafe39353614e5e281b818ebccc" - integrity sha512-iMQSGcpaecghDIh3mZEpZfoFH3ExBwTtuBEcvZ2XnGzCgQjeYXcMdIUwAfVQLXFTdHUHGF6Gu6/dFrYsCzySBQ== +"@react-stately/utils@^3.10.8": + version "3.10.8" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.8.tgz#fdb9d172f7bbc2d083e69190f5ef0edfa4b4392f" + integrity sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g== dependencies: "@swc/helpers" "^0.5.0" -"@react-types/breadcrumbs@^3.7.9": - version "3.7.9" - resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.9.tgz#c75eae6158bd3631854bff7521c2373b42b0e37c" - integrity sha512-eARYJo8J+VfNV8vP4uw3L2Qliba9wLV2bx9YQCYf5Lc/OE5B/y4gaTLz+Y2P3Rtn6gBPLXY447zCs5i7gf+ICg== +"@react-types/breadcrumbs@^3.7.15": + version "3.7.15" + resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.15.tgz#2b8b21aec32d2e328a4fa8b00f04f12908f6fed1" + integrity sha512-0RsymrsOAsx443XRDJ1krK+Lusr4t0qqExmzFe7/XYXOn/RbGKjzSdezsoWfTy8Hjks0YbfQPVKnNxg9LKv4XA== dependencies: - "@react-types/link" "^3.5.9" - "@react-types/shared" "^3.26.0" + "@react-types/link" "^3.6.3" + "@react-types/shared" "^3.31.0" -"@react-types/button@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.10.1.tgz#fc7ada2e83bc661b31c1473a82ec86dc11de057c" - integrity sha512-XTtap8o04+4QjPNAshFWOOAusUTxQlBjU2ai0BTVLShQEjHhRVDBIWsI2B2FKJ4KXT6AZ25llaxhNrreWGonmA== +"@react-types/button@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.13.0.tgz#a92ce8faa26bb27c7b44480b20dd35d732eaec4a" + integrity sha512-hwvcNnBjDeNvWheWfBhmkJSzC48ub5rZq0DnpemB3XKOvv5WcF9p6rrQZsQ3egNGkh0Z+bKfr2QfotgOkccHSw== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/calendar@^3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.5.0.tgz#a72fa15e08c7785b145005560baa35ad9b44627b" - integrity sha512-O3IRE7AGwAWYnvJIJ80cOy7WwoJ0m8GtX/qSmvXQAjC4qx00n+b5aFNBYAQtcyc3RM5QpW6obs9BfwGetFiI8w== +"@react-types/calendar@^3.7.3": + version "3.7.3" + resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.7.3.tgz#7850b45054aece3ac2303be2126c10078fd9c70f" + integrity sha512-gofPgVpSawJ0iGO01SbVH46u3gdykHlGT5BfGU1cRnsOR2tJX38dekO/rnuGsMQYF0+kU6U9YVae+XoOFJNnWg== dependencies: - "@internationalized/date" "^3.6.0" - "@react-types/shared" "^3.26.0" + "@internationalized/date" "^3.8.2" + "@react-types/shared" "^3.31.0" -"@react-types/checkbox@^3.9.0": - version "3.9.0" - resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.9.0.tgz#d4621fef81850543f7a028917e9c2781cd871443" - integrity sha512-9hbHx0Oo2Hp5a8nV8Q75LQR0DHtvOIJbFaeqESSopqmV9EZoYjtY/h0NS7cZetgahQgnqYWQi44XGooMDCsmxA== +"@react-types/checkbox@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.10.0.tgz#999933ee1b81feea80d2d9f2d0685be248cb5127" + integrity sha512-DJ84ilBDvZddE/Sul97Otee4M6psrPRaJm2a1Bc7M3Y5UKo6d6RGXdcDarRRpbnS7BeAbVanKiMS2ygI9QHh9g== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/color@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.0.1.tgz#42d49736cf606b8434d3fe0ab60b75bb0f44f554" - integrity sha512-KemFziO3GbmT3HEKrgOGdqNA6Gsmy9xrwFO3f8qXSG7gVz6M27Ic4R9HVQv4iAjap5uti6W13/pk2bc/jLVcEA== +"@react-types/color@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.1.0.tgz#20d6246b6f4fd3d0f483f16ed45822aed7b3b570" + integrity sha512-mqx76zdq/GyI7hdx+NTdTrCG6qmf1Uk3w/zWKF80OAesLqqs9XavQQZlRPu1Cg/fHiAHIBOLYTnLf8w+T2IMsw== dependencies: - "@react-types/shared" "^3.26.0" - "@react-types/slider" "^3.7.7" + "@react-types/shared" "^3.31.0" + "@react-types/slider" "^3.8.0" -"@react-types/combobox@^3.13.1": - version "3.13.1" - resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.1.tgz#d7d843f45501ad141f74ba62ed46d2e991b2d6a0" - integrity sha512-7xr+HknfhReN4QPqKff5tbKTe2kGZvH+DGzPYskAtb51FAAiZsKo+WvnNAvLwg3kRoC9Rkn4TAiVBp/HgymRDw== +"@react-types/combobox@^3.13.7": + version "3.13.7" + resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.7.tgz#ff050e930f44c6b0ad188885334f26fe00db634c" + integrity sha512-R7MQ4Qm4fryo6FCg3Vo/l9wxkYVG05trsLbxzMvvxCMkpcoHUPhy8Ll33eXA3YP74Rs/IaM9d0d/amSUZ4M9wg== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/datepicker@^3.9.0": - version "3.9.0" - resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.9.0.tgz#86e2a4e23e9fbf8299a12bd8aba9b1a52cf44725" - integrity sha512-dbKL5Qsm2MQwOTtVQdOcKrrphcXAqDD80WLlSQrBLg+waDuuQ7H+TrvOT0thLKloNBlFUGnZZfXGRHINpih/0g== +"@react-types/datepicker@^3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.13.0.tgz#18a826e0c96f25ccc1a9d891c92408a2d6ab931e" + integrity sha512-AG/iGcdQ5SVSjw8Ta7bCdGNkMda+e+Z7lOHxDawL44SII8LtZroBDlaCpb178Tvo17bBfJ6TvWXlvSpBY8GPRg== dependencies: - "@internationalized/date" "^3.6.0" - "@react-types/calendar" "^3.5.0" - "@react-types/overlays" "^3.8.11" - "@react-types/shared" "^3.26.0" + "@internationalized/date" "^3.8.2" + "@react-types/calendar" "^3.7.3" + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" -"@react-types/dialog@^3.5.14": - version "3.5.14" - resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.14.tgz#97e568dc38ede4312ba6a12eda855c5e32c7cd47" - integrity sha512-OXWMjrALwrlgw8aHD8SeRm/s3tbAssdaEh2h73KUSeFau3fU3n5mfKv+WnFqsEaOtN261o48l7hTlS6615H9AA== +"@react-types/dialog@^3.5.20": + version "3.5.20" + resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.20.tgz#195391fdb98d433370927d69fdbff4dc9006a8e6" + integrity sha512-ebn8jW/xW/nmRATaWIPHVBIpIFWSaqjrAxa58f5TXer5FtCD9pUuzAQDmy/o22ucB0yvn6Kl+fjb3SMbMdALZQ== dependencies: - "@react-types/overlays" "^3.8.11" - "@react-types/shared" "^3.26.0" + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" -"@react-types/grid@^3.2.10": - version "3.2.10" - resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.2.10.tgz#d2d1d124ed9472e3dedc48e91c941a7ad23bdc83" - integrity sha512-Z5cG0ITwqjUE4kWyU5/7VqiPl4wqMJ7kG/ZP7poAnLmwRsR8Ai0ceVn+qzp5nTA19cgURi8t3LsXn3Ar1FBoog== +"@react-types/grid@^3.3.4": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.3.4.tgz#02f196995a585e650ab9a4d569e20635ba0ddb30" + integrity sha512-8XNn7Czhl+D1b2zRwdO8c3oBJmKgevT/viKJB4qBVFOhK0l/p3HYDZUMdeclvUfSt4wx4ASpI7MD3v1vmN54oA== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/link@^3.5.9": - version "3.5.9" - resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.5.9.tgz#bf61ff2780581de03920e6e43260844a81a38d2f" - integrity sha512-JcKDiDMqrq/5Vpn+BdWQEuXit4KN4HR/EgIi3yKnNbYkLzxBoeQZpQgvTaC7NEQeZnSqkyXQo3/vMUeX/ZNIKw== +"@react-types/link@^3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.6.3.tgz#ba223e8a2478c17d344dc286ac7a7a92dc1137d0" + integrity sha512-XIYEl9ZPa5mLy8uGQabdhPaFVmnvxNSYF59t0vs/IV0yxeoPvrjKjRAbXS+WP9zYMXIkHYNYYucriCkqKhotJA== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/listbox@^3.5.3": - version "3.5.3" - resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.5.3.tgz#c5dbe8a67d67ca59de6b88aaa2f20fcf61fee1c5" - integrity sha512-v1QXd9/XU3CCKr2Vgs7WLcTr6VMBur7CrxHhWZQQFExsf9bgJ/3wbUdjy4aThY/GsYHiaS38EKucCZFr1QAfqA== +"@react-types/listbox@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.7.2.tgz#36d7b1dcad36814d3f16abcc8ec6889b78934856" + integrity sha512-MRpBhApR1jJNASoVWsEvH5vf89TJw+l9Lt1ssawop0K2iYF5PmkthRdqcpYcTkFu5+f5QvFchVsNJ3TKD4cf2A== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/menu@^3.9.13": - version "3.9.13" - resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.9.13.tgz#a666c2233cbdb495202586df86a798601788f74d" - integrity sha512-7SuX6E2tDsqQ+HQdSvIda1ji/+ujmR86dtS9CUu5yWX91P25ufRjZ72EvLRqClWNQsj1Xl4+2zBDLWlceznAjw== +"@react-types/menu@^3.10.3": + version "3.10.3" + resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.10.3.tgz#36fe24dc3d622524388e0ea9cecdfb8e013a7365" + integrity sha512-Vd3t7fEbIOiq7kBAHaihfYf+/3Fuh0yK2KNjJ70BPtlAhMRMDVG3m0PheSTm3FFfj+uAdQdfc2YKPnMBbWjDuQ== dependencies: - "@react-types/overlays" "^3.8.11" - "@react-types/shared" "^3.26.0" + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" -"@react-types/meter@^3.4.5": - version "3.4.5" - resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.5.tgz#e06d4a2fabd24989c73541b032123c5de495b613" - integrity sha512-04w1lEtvP/c3Ep8ND8hhH2rwjz2MtQ8o8SNLhahen3u0rX3jKOgD4BvHujsyvXXTMjj1Djp74sGzNawb4Ppi9w== +"@react-types/meter@^3.4.11": + version "3.4.11" + resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.11.tgz#dd3d59fbd90437af450d84799266817e526528b9" + integrity sha512-c4jnDWFxDp09fNpCDrq6l2RxOxcolmf/frvdtVA/d4SGvfEOoqeUakpVDuOqDD0bU58tQPG3fqT2zH8vpWiJew== dependencies: - "@react-types/progress" "^3.5.8" + "@react-types/progress" "^3.5.14" -"@react-types/numberfield@^3.8.7": - version "3.8.7" - resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.7.tgz#5a697fdf1bc405dbf55dafed713d47ed79f8e54b" - integrity sha512-KccMPi39cLoVkB2T0V7HW6nsxQVAwt89WWCltPZJVGzsebv/k0xTQlPVAgrUake4kDLoE687e3Fr/Oe3+1bDhw== +"@react-types/numberfield@^3.8.13": + version "3.8.13" + resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.13.tgz#9939992551d4b2a08f7d1d8b71879096c2207440" + integrity sha512-zRSqInmxOTQJZt2fjAhuQK3Wa1vCOlKsRzUVvxTrE8gtQxlgFxirmobuUnjTEhwkFyb0bq8GvVfQV1E95Si2yw== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/overlays@^3.8.11": - version "3.8.11" - resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.8.11.tgz#313964703b2a23572138120b619d35da33445dfd" - integrity sha512-aw7T0rwVI3EuyG5AOaEIk8j7dZJQ9m34XAztXJVZ/W2+4pDDkLDbJ/EAPnuo2xGYRGhowuNDn4tDju01eHYi+w== +"@react-types/overlays@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.9.0.tgz#c0fe30052b6795e549a0748733c84bd1d63ac9fc" + integrity sha512-T2DqMcDN5p8vb4vu2igoLrAtuewaNImLS8jsK7th7OjwQZfIWJn5Y45jSxHtXJUddEg1LkUjXYPSXCMerMcULw== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/progress@^3.5.8": - version "3.5.8" - resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.8.tgz#62ce4207c7e8d640b794c6d89063ce21bdb5970d" - integrity sha512-PR0rN5mWevfblR/zs30NdZr+82Gka/ba7UHmYOW9/lkKlWeD7PHgl1iacpd/3zl/jUF22evAQbBHmk1mS6Mpqw== +"@react-types/progress@^3.5.14": + version "3.5.14" + resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.14.tgz#4ac5e15471c015105169778c5befdb1283735b8e" + integrity sha512-GeGrjOeHR/p5qQ1gGlN68jb+lL47kuddxMgdR1iEnAlYGY4OtJoEN/EM5W2ZxJRKPcJmzdcY/p/J0PXa8URbSg== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/radio@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.8.5.tgz#8e2dd1911fba829b7f1ebb40bccf9ca483f021fc" - integrity sha512-gSImTPid6rsbJmwCkTliBIU/npYgJHOFaI3PNJo7Y0QTAnFelCtYeFtBiWrFodSArSv7ASqpLLUEj9hZu/rxIg== +"@react-types/radio@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.9.0.tgz#72e0b455e361407b2323932081da9dd692e1c1f1" + integrity sha512-phndlgqMF6/9bOOhO3le00eozNfDU1E7OHWV2cWWhGSMRFuRdf7/d+NjVtavCX75+GJ50MxvXk+KB0fjTuvKyg== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/searchfield@^3.5.10": - version "3.5.10" - resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.5.10.tgz#015a42bf8417618b848035b88f0aba98572beceb" - integrity sha512-7wW4pJzbReawoGPu8a4l+CODTCDN088EN/ysUzl622ewim57PjArjix+lpO4+aEtJqS9HKpq8UEbjwo9axpcUA== +"@react-types/searchfield@^3.6.4": + version "3.6.4" + resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.6.4.tgz#96962e1f788e7d1854cd630ec6ecb2cacca01a2f" + integrity sha512-gRVWnRHf7pqU0lBVlkU6XsLxvaWTPnn0EomddIBCVh0msVIyvEea8CXJppu7EpvRh+grNpiMEYeijQ+u8hixlQ== dependencies: - "@react-types/shared" "^3.26.0" - "@react-types/textfield" "^3.10.0" + "@react-types/shared" "^3.31.0" + "@react-types/textfield" "^3.12.4" -"@react-types/select@^3.9.8": - version "3.9.8" - resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.9.8.tgz#2443b82549b65821f85876a5b803e6d04ae6343e" - integrity sha512-RGsYj2oFjXpLnfcvWMBQnkcDuKkwT43xwYWZGI214/gp/B64tJiIUgTM5wFTRAeGDX23EePkhCQF+9ctnqFd6g== +"@react-types/select@^3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.10.0.tgz#19b843c532aea4e72597f77f076e656e8ca975a0" + integrity sha512-+xJwYWJoJTCGsaiPAqb6QB79ub1WKIHSmOS9lh/fPUXfUszVs05jhajaN9KjrKmnXds5uh4u6l1JH5J1l2K5pw== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/shared@^3.25.0", "@react-types/shared@^3.26.0": - version "3.26.0" - resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.26.0.tgz#21a8b579f0097ee78de18e3e580421ced89e4c8c" - integrity sha512-6FuPqvhmjjlpEDLTiYx29IJCbCNWPlsyO+ZUmCUXzhUv2ttShOXfw8CmeHWHftT/b2KweAWuzqSlfeXPR76jpw== +"@react-types/shared@^3.25.0", "@react-types/shared@^3.31.0": + version "3.31.0" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.31.0.tgz#014be53096c3728f0684550430807e9962365c15" + integrity sha512-ua5U6V66gDcbLZe4P2QeyNgPp4YWD1ymGA6j3n+s8CGExtrCPe64v+g4mvpT8Bnb985R96e4zFT61+m0YCwqMg== -"@react-types/slider@^3.7.7": - version "3.7.7" - resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.7.7.tgz#f00450c6268665ff2ad38ad69bdf51d84ff2341a" - integrity sha512-lYTR9zXQV2fSEm/G3gwDENWiki1IXd/oorsgf0zu1DBi2SQDbOsLsGUXiwvD24Xy6OkUuhAqjLPPexezo7+u9g== +"@react-types/slider@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.8.0.tgz#89994e9d3debb001b2a99b4a0f4afd8e5c0c45e8" + integrity sha512-eN6Fd3YCPseGfvfOJDtn9Lh9CrAb8tF3cTAprEcpnGrsxmdW9JQpcuciYuLM871X5D2fYg4WaYMpZaiYssjxBQ== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/switch@^3.5.7": - version "3.5.7" - resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.7.tgz#f3fb589fce5819ca1c15f12479bf348e053adc27" - integrity sha512-1IKiq510rPTHumEZuhxuazuXBa2Cuxz6wBIlwf3NCVmgWEvU+uk1ETG0sH2yymjwCqhtJDKXi+qi9HSgPEDwAg== +"@react-types/switch@^3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.13.tgz#6dbbef224874bc0f3a956c664152653ce4cec759" + integrity sha512-C2EhKBu7g7xhKboPPxhyKtROEti80Ck7TBnKclXt0D4LiwbzpR3qGfuzB+7YFItnhiauP7Uxe+bAfM5ojjtm9w== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/table@^3.10.3": - version "3.10.3" - resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.10.3.tgz#33959348641500e406abe330074f84b0c75ae4ac" - integrity sha512-Ac+W+m/zgRzlTU8Z2GEg26HkuJFswF9S6w26r+R3MHwr8z2duGPvv37XRtE1yf3dbpRBgHEAO141xqS2TqGwNg== +"@react-types/table@^3.13.2": + version "3.13.2" + resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.13.2.tgz#c4becb119e1ecbe35be2ec9e9d198bbeedf120bd" + integrity sha512-3/BpFIWHXTcGgQEfip87gMNCWPtPNsc3gFkW4qtsevQ+V0577KyNyvQgvFrqMZKnvz3NWFKyshBb7PTevsus4Q== dependencies: - "@react-types/grid" "^3.2.10" - "@react-types/shared" "^3.26.0" + "@react-types/grid" "^3.3.4" + "@react-types/shared" "^3.31.0" -"@react-types/tabs@^3.3.11": - version "3.3.11" - resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.11.tgz#b7db710ce2ca42a4e72cd2a581070212d2b07793" - integrity sha512-BjF2TqBhZaIcC4lc82R5pDJd1F7kstj1K0Nokhz99AGYn8C0ITdp6lR+DPVY9JZRxKgP9R2EKfWGI90Lo7NQdA== +"@react-types/tabs@^3.3.17": + version "3.3.17" + resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.17.tgz#f6fb284077d1091a4513f56b2d35a386a9711f37" + integrity sha512-cLcdxWNJe0Kf/pKuPQbEF9Fl+axiP4gB/WVjmAdhCgQ5LCJw2dGcy1LI1SXrlS3PVclbnujD1DJ8z1lIW4Tmww== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/textfield@^3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.10.0.tgz#10df39b75334174490a539ecae71ad19f5ea074d" - integrity sha512-ShU3d6kLJGQjPXccVFjM3KOXdj3uyhYROqH9YgSIEVxgA9W6LRflvk/IVBamD9pJYTPbwmVzuP0wQkTDupfZ1w== +"@react-types/textfield@^3.12.4": + version "3.12.4" + resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.12.4.tgz#f95c359c5fef4cd24abf7969d3c28de77c8e1ecf" + integrity sha512-cOgzI1dT8X1JMNQ9u2UKoV2L28ROkbFEtzY9At0MqTZYYSxYp3Q7i+XRqIBehu8jOMuCtN9ed9EgwVSfkicyLQ== dependencies: - "@react-types/shared" "^3.26.0" + "@react-types/shared" "^3.31.0" -"@react-types/tooltip@^3.4.13": - version "3.4.13" - resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.13.tgz#f73fdc5c56790b7bd7c0d5382d0c758bd659e9d7" - integrity sha512-KPekFC17RTT8kZlk7ZYubueZnfsGTDOpLw7itzolKOXGddTXsrJGBzSB4Bb060PBVllaDO0MOrhPap8OmrIl1Q== +"@react-types/tooltip@^3.4.19": + version "3.4.19" + resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.19.tgz#2f30b83a0f36ad2e2d1f75531d0d6f30abb525a4" + integrity sha512-OR/pwZReWbCIxuHJYB1L4fTwliA+mzVvUJMWwXIRy6Eh5d07spS3FZEKFvOgjMxA1nyv5PLf8eyr5RuuP1GGAA== dependencies: - "@react-types/overlays" "^3.8.11" - "@react-types/shared" "^3.26.0" + "@react-types/overlays" "^3.9.0" + "@react-types/shared" "^3.31.0" -"@remix-run/router@1.19.0": - version "1.19.0" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.19.0.tgz#745dbffbce67f05386d57ca22c51dfd85c979593" - integrity sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA== +"@remix-run/router@1.23.0": + version "1.23.0" + resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.23.0.tgz#35390d0e7779626c026b11376da6789eb8389242" + integrity sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA== -"@rolldown/pluginutils@1.0.0-beta.9": - version "1.0.0-beta.9" - resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.9.tgz#68ef9fff5a9791a642cea0dc4380ce6cb487a84a" - integrity sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w== +"@rolldown/pluginutils@1.0.0-beta.27": + version "1.0.0-beta.27" + resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz#47d2bf4cef6d470b22f5831b420f8964e0bf755f" + integrity sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA== -"@segment/analytics-core@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.6.0.tgz#f59cdc45a4408a09fdae77910f5a0b43833e8af8" - integrity sha512-bn9X++IScUfpT7aJGjKU/yJAu/Ko2sYD6HsKA70Z2560E89x30pqgqboVKY8kootvQnT4UKCJiUr5NDMgjmWdQ== +"@segment/analytics-core@1.8.2": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.8.2.tgz#f8aea312af3655e6483d0bdc160f0e05484529ab" + integrity sha512-5FDy6l8chpzUfJcNlIcyqYQq4+JTUynlVoCeCUuVz+l+6W0PXg+ljKp34R4yLVCcY5VVZohuW+HH0VLWdwYVAg== dependencies: "@lukeed/uuid" "^2.0.0" "@segment/analytics-generic-utils" "1.2.0" - dset "^3.1.2" + dset "^3.1.4" tslib "^2.4.1" "@segment/analytics-generic-utils@1.2.0": @@ -2033,21 +1994,29 @@ tslib "^2.4.1" "@segment/analytics-next@^1.70.0": - version "1.72.1" - resolved "https://registry.yarnpkg.com/@segment/analytics-next/-/analytics-next-1.72.1.tgz#e09bc6a31de004986c1822ac39c69b419135c75e" - integrity sha512-OeCe/jMAWxC5a1fY8RRszIzG7zevmkRHEaUQZMXskPFPWu2fB9r8A/JeZtoX9+kKlNg2SMMAdsnIRxsvaHIkMA== + version "1.81.1" + resolved "https://registry.yarnpkg.com/@segment/analytics-next/-/analytics-next-1.81.1.tgz#1e98c44090c95c131c249aaf8ad48aa4afb964e1" + integrity sha512-nVHNhriViptjkp4004qBbvmnW9/3brjhBv2P5Cvcg7iWW41fBzUY8FbLi+8wkmSbycT9fH1pTM3TUxB6+h0Fcg== dependencies: "@lukeed/uuid" "^2.0.0" - "@segment/analytics-core" "1.6.0" + "@segment/analytics-core" "1.8.2" "@segment/analytics-generic-utils" "1.2.0" + "@segment/analytics-page-tools" "1.0.0" "@segment/analytics.js-video-plugins" "^0.2.1" "@segment/facade" "^3.4.9" - dset "^3.1.2" + dset "^3.1.4" js-cookie "3.0.1" node-fetch "^2.6.7" tslib "^2.4.1" unfetch "^4.1.0" +"@segment/analytics-page-tools@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@segment/analytics-page-tools/-/analytics-page-tools-1.0.0.tgz#f5fb9b8f0c1e80e821b0a77ca13ac53daf08a28a" + integrity sha512-o9OVB91qLB9qb0Bw1HfjmWm5AnrMNULRjx++4lBqLt8InKRX1urrRBparVlpj+yJA0sckN5ZcsfazRLuPgBYDQ== + dependencies: + tslib "^2.4.1" + "@segment/analytics.js-video-plugins@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@segment/analytics.js-video-plugins/-/analytics.js-video-plugins-0.2.1.tgz#3596fa3887dcd9df5978dc566edf4a0aea2a9b1e" @@ -2078,116 +2047,149 @@ integrity sha512-BtanDuvJqnACFkeeYje7pWULVv8RgZaqKHWwGFnL/g/TH/CcZjkIVTfGDp/MAxmilYHUkrX70SqwnYSTNEaN7A== "@swc/helpers@^0.5.0": - version "0.5.12" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.12.tgz#37aaca95284019eb5d2207101249435659709f4b" - integrity sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g== + version "0.5.17" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.17.tgz#5a7be95ac0f0bf186e7e6e890e7a6f6cda6ce971" + integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A== dependencies: - tslib "^2.4.0" + tslib "^2.8.0" -"@tailwindcss/node@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.0.12.tgz#0f89ad2537eafe65a35ec4400b42142de918bafc" - integrity sha512-a6J11K1Ztdln9OrGfoM75/hChYPcHYGNYimqciMrvKXRmmPaS8XZTHhdvb5a3glz4Kd4ZxE1MnuFE2c0fGGmtg== +"@tailwindcss/node@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.11.tgz#d626af65fc9872e5e9d8884791d7e3856e945359" + integrity sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q== dependencies: + "@ampproject/remapping" "^2.3.0" enhanced-resolve "^5.18.1" jiti "^2.4.2" - tailwindcss "4.0.12" - -"@tailwindcss/oxide-android-arm64@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.12.tgz#f79cf637bc11b0ae71e75b66d7c5ba5159bd3df3" - integrity sha512-dAXCaemu3mHLXcA5GwGlQynX8n7tTdvn5i1zAxRvZ5iC9fWLl5bGnjZnzrQqT7ttxCvRwdVf3IHUnMVdDBO/kQ== - -"@tailwindcss/oxide-darwin-arm64@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.12.tgz#6b730b5d19ff01748a27af5103966f534a899f07" - integrity sha512-vPNI+TpJQ7sizselDXIJdYkx9Cu6JBdtmRWujw9pVIxW8uz3O2PjgGGzL/7A0sXI8XDjSyRChrUnEW9rQygmJQ== - -"@tailwindcss/oxide-darwin-x64@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.12.tgz#2eb33ba40cbb78922004be9d6b81542347043fe5" - integrity sha512-RL/9jM41Fdq4Efr35C5wgLx98BirnrfwuD+zgMFK6Ir68HeOSqBhW9jsEeC7Y/JcGyPd3MEoJVIU4fAb7YLg7A== - -"@tailwindcss/oxide-freebsd-x64@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.12.tgz#317b980504b0bbcaee32c9e4e961f77cdadb02a6" - integrity sha512-7WzWiax+LguJcMEimY0Q4sBLlFXu1tYxVka3+G2M9KmU/3m84J3jAIV4KZWnockbHsbb2XgrEjtlJKVwHQCoRA== - -"@tailwindcss/oxide-linux-arm-gnueabihf@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.12.tgz#0f7153dec6e200327b76775ad2d1154706cef34d" - integrity sha512-X9LRC7jjE1QlfIaBbXjY0PGeQP87lz5mEfLSVs2J1yRc9PSg1tEPS9NBqY4BU9v5toZgJgzKeaNltORyTs22TQ== - -"@tailwindcss/oxide-linux-arm64-gnu@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.12.tgz#50a3ec46600cc998f45a265ebdd5de2d7bb27ee0" - integrity sha512-i24IFNq2402zfDdoWKypXz0ZNS2G4NKaA82tgBlE2OhHIE+4mg2JDb5wVfyP6R+MCm5grgXvurcIcKWvo44QiQ== - -"@tailwindcss/oxide-linux-arm64-musl@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.12.tgz#2de10c5239766e2fb810045fe5b75db54d481fd4" - integrity sha512-LmOdshJBfAGIBG0DdBWhI0n5LTMurnGGJCHcsm9F//ISfsHtCnnYIKgYQui5oOz1SUCkqsMGfkAzWyNKZqbGNw== - -"@tailwindcss/oxide-linux-x64-gnu@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.12.tgz#f89a24ffb0f14ea23d110efcbf58baa1db783582" - integrity sha512-OSK667qZRH30ep8RiHbZDQfqkXjnzKxdn0oRwWzgCO8CoTxV+MvIkd0BWdQbYtYuM1wrakARV/Hwp0eA/qzdbw== - -"@tailwindcss/oxide-linux-x64-musl@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.12.tgz#c53a5b494e241a744f067ba3a261adca80c20af4" - integrity sha512-uylhWq6OWQ8krV8Jk+v0H/3AZKJW6xYMgNMyNnUbbYXWi7hIVdxRKNUB5UvrlC3RxtgsK5EAV2i1CWTRsNcAnA== - -"@tailwindcss/oxide-win32-arm64-msvc@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.12.tgz#63c0befad43355fb5cea6c64efd946a718acb06b" - integrity sha512-XDLnhMoXZEEOir1LK43/gHHwK84V1GlV8+pAncUAIN2wloeD+nNciI9WRIY/BeFTqES22DhTIGoilSO39xDb2g== - -"@tailwindcss/oxide-win32-x64-msvc@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.12.tgz#d8fabbdc86d323ca29f5ef298c20f651585ed402" - integrity sha512-I/BbjCLpKDQucvtn6rFuYLst1nfFwSMYyPzkx/095RE+tuzk5+fwXuzQh7T3fIBTcbn82qH/sFka7yPGA50tLw== - -"@tailwindcss/oxide@4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.0.12.tgz#2db7c930d2c6fe29ee14a996891b21401650189a" - integrity sha512-DWb+myvJB9xJwelwT9GHaMc1qJj6MDXRDR0CS+T8IdkejAtu8ctJAgV4r1drQJLPeS7mNwq2UHW2GWrudTf63A== + lightningcss "1.30.1" + magic-string "^0.30.17" + source-map-js "^1.2.1" + tailwindcss "4.1.11" + +"@tailwindcss/oxide-android-arm64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz#1f387d8302f011b61c226deb0c3a1d2bd79c6915" + integrity sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg== + +"@tailwindcss/oxide-darwin-arm64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz#acd35ffb7e4eae83d0a3fe2f8ea36cfcc9b21f7e" + integrity sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ== + +"@tailwindcss/oxide-darwin-x64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz#a0022312993a3893d6ff0312d6e3c83c4636fef4" + integrity sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw== + +"@tailwindcss/oxide-freebsd-x64@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz#dd8e55eb0b88fe7995b8148c0e0ae5fa27092d22" + integrity sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz#02ee99090988847d3f13d277679012cbffcdde37" + integrity sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz#4837559c102bebe65089879f6a0278ed473b4813" + integrity sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz#bec465112a13a1383558ff36afdf28b8a8cb9021" + integrity sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz#f9e47e6aa67ff77f32f7412bc9698d4278e101bf" + integrity sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg== + +"@tailwindcss/oxide-linux-x64-musl@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz#7d6e8adcfb9bc84d8e2e2e8781d661edb9e41ba8" + integrity sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q== + +"@tailwindcss/oxide-wasm32-wasi@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz#a1762f4939c6ebaa824696fda2fd7db1b85fbed2" + integrity sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@emnapi/wasi-threads" "^1.0.2" + "@napi-rs/wasm-runtime" "^0.2.11" + "@tybys/wasm-util" "^0.9.0" + tslib "^2.8.0" + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz#70ba392dca0fa3707ebe27d2bd6ac3e69d35e3b7" + integrity sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w== + +"@tailwindcss/oxide-win32-x64-msvc@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz#cdcb9eea9225a346c0695f67f621990b0534763f" + integrity sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg== + +"@tailwindcss/oxide@4.1.11": + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.1.11.tgz#569b668c99c337b7b8204bc5b6a833429755a05b" + integrity sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg== + dependencies: + detect-libc "^2.0.4" + tar "^7.4.3" optionalDependencies: - "@tailwindcss/oxide-android-arm64" "4.0.12" - "@tailwindcss/oxide-darwin-arm64" "4.0.12" - "@tailwindcss/oxide-darwin-x64" "4.0.12" - "@tailwindcss/oxide-freebsd-x64" "4.0.12" - "@tailwindcss/oxide-linux-arm-gnueabihf" "4.0.12" - "@tailwindcss/oxide-linux-arm64-gnu" "4.0.12" - "@tailwindcss/oxide-linux-arm64-musl" "4.0.12" - "@tailwindcss/oxide-linux-x64-gnu" "4.0.12" - "@tailwindcss/oxide-linux-x64-musl" "4.0.12" - "@tailwindcss/oxide-win32-arm64-msvc" "4.0.12" - "@tailwindcss/oxide-win32-x64-msvc" "4.0.12" + "@tailwindcss/oxide-android-arm64" "4.1.11" + "@tailwindcss/oxide-darwin-arm64" "4.1.11" + "@tailwindcss/oxide-darwin-x64" "4.1.11" + "@tailwindcss/oxide-freebsd-x64" "4.1.11" + "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.11" + "@tailwindcss/oxide-linux-arm64-gnu" "4.1.11" + "@tailwindcss/oxide-linux-arm64-musl" "4.1.11" + "@tailwindcss/oxide-linux-x64-gnu" "4.1.11" + "@tailwindcss/oxide-linux-x64-musl" "4.1.11" + "@tailwindcss/oxide-wasm32-wasi" "4.1.11" + "@tailwindcss/oxide-win32-arm64-msvc" "4.1.11" + "@tailwindcss/oxide-win32-x64-msvc" "4.1.11" "@tailwindcss/postcss@^4.0.12": - version "4.0.12" - resolved "https://registry.yarnpkg.com/@tailwindcss/postcss/-/postcss-4.0.12.tgz#eea9e278317338db58fd5752b6982215ad37a77e" - integrity sha512-r59Sdr8djCW4dL3kvc4aWU8PHdUAVM3O3te2nbYzXsWwKLlHPCuUoZAc9FafXb/YyNDZOMI7sTbKTKFmwOrMjw== + version "4.1.11" + resolved "https://registry.yarnpkg.com/@tailwindcss/postcss/-/postcss-4.1.11.tgz#4d844f7ff295c731ceab54934531bece7380ce0c" + integrity sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA== dependencies: "@alloc/quick-lru" "^5.2.0" - "@tailwindcss/node" "4.0.12" - "@tailwindcss/oxide" "4.0.12" - lightningcss "^1.29.1" + "@tailwindcss/node" "4.1.11" + "@tailwindcss/oxide" "4.1.11" postcss "^8.4.41" - tailwindcss "4.0.12" + tailwindcss "4.1.11" "@tanstack/react-table@^8.20.5": - version "8.20.5" - resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.20.5.tgz#19987d101e1ea25ef5406dce4352cab3932449d8" - integrity sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA== + version "8.21.3" + resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.21.3.tgz#2c38c747a5731c1a07174fda764b9c2b1fb5e91b" + integrity sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww== + dependencies: + "@tanstack/table-core" "8.21.3" + +"@tanstack/table-core@8.21.3": + version "8.21.3" + resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.21.3.tgz#2977727d8fc8dfa079112d9f4d4c019110f1732c" + integrity sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg== + +"@tybys/wasm-util@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" + integrity sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ== dependencies: - "@tanstack/table-core" "8.20.5" + tslib "^2.4.0" -"@tanstack/table-core@8.20.5": - version "8.20.5" - resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.20.5.tgz#3974f0b090bed11243d4107283824167a395cf1d" - integrity sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg== +"@tybys/wasm-util@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" + integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== + dependencies: + tslib "^2.4.0" "@types/babel__core@^7.20.5": version "7.20.5" @@ -2201,9 +2203,9 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" - integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== dependencies: "@babel/types" "^7.0.0" @@ -2216,11 +2218,11 @@ "@babel/types" "^7.0.0" "@types/babel__traverse@*": - version "7.20.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" - integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== dependencies: - "@babel/types" "^7.20.7" + "@babel/types" "^7.28.2" "@types/chroma-js@2.1.4": version "2.1.4" @@ -2242,9 +2244,9 @@ "@types/estree" "*" "@types/estree@*", "@types/estree@^1.0.0": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== "@types/hast@^2.0.0": version "2.3.10" @@ -2265,11 +2267,6 @@ resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA== -"@types/json-schema@^7.0.12": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - "@types/mdast@^4.0.0": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6" @@ -2278,16 +2275,16 @@ "@types/unist" "*" "@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" + integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== "@types/node@^22.13.10": - version "22.13.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.10.tgz#df9ea358c5ed991266becc3109dc2dc9125d77e4" - integrity sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw== + version "22.17.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.17.0.tgz#e8c9090e957bd4d9860efb323eb92d297347eac7" + integrity sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ== dependencies: - undici-types "~6.20.0" + undici-types "~6.21.0" "@types/parse-json@^4.0.0": version "4.0.2" @@ -2295,46 +2292,37 @@ integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== "@types/prop-types@*", "@types/prop-types@^15.7.12": - version "15.7.12" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" - integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + version "15.7.15" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7" + integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw== "@types/react-dom@^18.2.7": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== - dependencies: - "@types/react" "*" + version "18.3.7" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.7.tgz#b89ddf2cd83b4feafcc4e2ea41afdfb95a0d194f" + integrity sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ== "@types/react-transition-group@^4.4.0", "@types/react-transition-group@^4.4.10": - version "4.4.10" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" - integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q== - dependencies: - "@types/react" "*" + version "4.4.12" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044" + integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== -"@types/react@*", "@types/react@^18.2.15": - version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== +"@types/react@^18.2.15": + version "18.3.23" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.23.tgz#86ae6f6b95a48c418fecdaccc8069e0fbb63696a" + integrity sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w== dependencies: "@types/prop-types" "*" csstype "^3.0.2" -"@types/semver@^7.5.0": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== - "@types/unist@*", "@types/unist@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20" - integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" + integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== "@types/unist@^2", "@types/unist@^2.0.0": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.10.tgz#04ffa7f406ab628f7f7e97ca23e290cd8ab15efc" - integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" + integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== "@types/uuid@^10.0.0": version "10.0.0" @@ -2342,21 +2330,19 @@ integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== "@typescript-eslint/eslint-plugin@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.0.tgz#62cda0d35bbf601683c6e58cf5d04f0275caca4e" - integrity sha512-M72SJ0DkcQVmmsbqlzc6EJgb/3Oz2Wdm6AyESB4YkGgCxP8u5jt5jn4/OBMPK3HLOxcttZq5xbBBU7e2By4SZQ== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "7.0.0" - "@typescript-eslint/type-utils" "7.0.0" - "@typescript-eslint/utils" "7.0.0" - "@typescript-eslint/visitor-keys" "7.0.0" - debug "^4.3.4" + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3" + integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/type-utils" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" graphemer "^1.4.0" - ignore "^5.2.4" + ignore "^5.3.1" natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" + ts-api-utils "^1.3.0" "@typescript-eslint/parser@^6.0.0": version "6.21.0" @@ -2377,33 +2363,33 @@ "@typescript-eslint/types" "6.21.0" "@typescript-eslint/visitor-keys" "6.21.0" -"@typescript-eslint/scope-manager@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.0.0.tgz#15ea9abad2b56fc8f5c0b516775f41c86c5c8685" - integrity sha512-IxTStwhNDPO07CCrYuAqjuJ3Xf5MrMaNgbAZPxFXAUpAtwqFxiuItxUaVtP/SJQeCdJjwDGh9/lMOluAndkKeg== +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== dependencies: - "@typescript-eslint/types" "7.0.0" - "@typescript-eslint/visitor-keys" "7.0.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" -"@typescript-eslint/type-utils@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.0.0.tgz#a4c7ae114414e09dbbd3c823b5924793f7483252" - integrity sha512-FIM8HPxj1P2G7qfrpiXvbHeHypgo2mFpFGoh5I73ZlqmJOsloSa1x0ZyXCer43++P1doxCgNqIOLqmZR6SOT8g== +"@typescript-eslint/type-utils@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b" + integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== dependencies: - "@typescript-eslint/typescript-estree" "7.0.0" - "@typescript-eslint/utils" "7.0.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils" "7.18.0" debug "^4.3.4" - ts-api-utils "^1.0.1" + ts-api-utils "^1.3.0" "@typescript-eslint/types@6.21.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== -"@typescript-eslint/types@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.0.0.tgz#2e5889c7fe3c873fc6dc6420aa77775f17cd5dc6" - integrity sha512-9ZIJDqagK1TTs4W9IyeB2sH/s1fFhN9958ycW8NRTg1vXGzzH5PQNzq6KbsbVGMT+oyyfa17DfchHDidcmf5cg== +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== "@typescript-eslint/typescript-estree@6.21.0": version "6.21.0" @@ -2419,32 +2405,29 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/typescript-estree@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.0.tgz#7ce66f2ce068517f034f73fba9029300302fdae9" - integrity sha512-JzsOzhJJm74aQ3c9um/aDryHgSHfaX8SHFIu9x4Gpik/+qxLvxUylhTsO9abcNu39JIdhY2LgYrFxTii3IajLA== +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== dependencies: - "@typescript-eslint/types" "7.0.0" - "@typescript-eslint/visitor-keys" "7.0.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.0.0.tgz#e43710af746c6ae08484f7afc68abc0212782c7e" - integrity sha512-kuPZcPAdGcDBAyqDn/JVeJVhySvpkxzfXjJq1X1BFSTYo1TTuo4iyb937u457q4K0In84p6u2VHQGaFnv7VYqg== +"@typescript-eslint/utils@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "7.0.0" - "@typescript-eslint/types" "7.0.0" - "@typescript-eslint/typescript-estree" "7.0.0" - semver "^7.5.4" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" "@typescript-eslint/visitor-keys@6.21.0": version "6.21.0" @@ -2454,28 +2437,229 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@typescript-eslint/visitor-keys@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.0.tgz#83cdadd193ee735fe9ea541f6a2b4d76dfe62081" - integrity sha512-JZP0uw59PRHp7sHQl3aF/lFgwOW2rgNVnXUksj1d932PMita9wFBd3621vHQRDvHwPsSY9FMAAHVc8gTvLYY4w== +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== dependencies: - "@typescript-eslint/types" "7.0.0" - eslint-visitor-keys "^3.4.1" + "@typescript-eslint/types" "7.18.0" + eslint-visitor-keys "^3.4.3" + +"@uiw/color-convert@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/color-convert/-/color-convert-2.5.4.tgz#b42473cf5a70e6acb80be92daa01ce15b80e12e1" + integrity sha512-gcVsu9SfEbob9SJggmlrDhMp6bngqsEqjr7KYM86Ltq5wghmvfUnJlvVd6HxLjuGFlqy5zqbK1Z6GDLDoSmsWg== + +"@uiw/react-color-alpha@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-alpha/-/react-color-alpha-2.5.4.tgz#539a4b3fab6f57f875c0c9c67c0e42870ec987b5" + integrity sha512-TZDAsEBMlGaEa4P8nz6ZLSDa1c+XdZZ26+Hkb1rf+h2qDYSPQx8gijtiSgm+ePZGp+4+IqoG2jfXuHwAEWycmg== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-drag-event-interactive" "2.5.4" + +"@uiw/react-color-block@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-block/-/react-color-block-2.5.4.tgz#c1c36a2087fac020939ee03a5dc0e7dbf2080c91" + integrity sha512-weW/nteJNBklKrwZxLmDjxXaQ3LrkESkqh0iazzwwgY0fWh8xC/PV5TzZ2HpAMwYoB9MTRk06CsMqHSPinncMw== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-chrome@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-chrome/-/react-color-chrome-2.5.4.tgz#61295e66552a675b517de670d0aa3a35e0984ebd" + integrity sha512-jNLKCGrvkYh9UYAm/tV79gijUGFp5XlaQ3cL+Wk6gr1UIfTfwLNpr3QqZbhfdvUF8s5V1/hs64hFR6GE4PVB9Q== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-hsla" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-github" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + +"@uiw/react-color-circle@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-circle/-/react-color-circle-2.5.4.tgz#54a4bfc55a7d231f778f5abc2fbd8c5afdd1cbab" + integrity sha512-EaAZs9qsOhkFD74yx00hmd0RmCP5cKq691PZC47LDRK1o7IK05VYtcoBEL3zx8TBtUyk1A5gg1GRBRe/KxpK6w== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-colorful@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-colorful/-/react-color-colorful-2.5.4.tgz#f9692fc0ef8e441511af50364e937294e897c56f" + integrity sha512-4QQt+QjNlytdeLL4pSI2ZneN6KEMG4oPkuqTZhRwJvuS4xGonCgg542egRaBJAlszwNy/1ix82SrMAGR9sW+Bw== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + +"@uiw/react-color-compact@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-compact/-/react-color-compact-2.5.4.tgz#853ef7dd1c2d3a4029db43e1a1e9ad742d34e996" + integrity sha512-6m/qIchCvGkYzekeATgCvIodV6ORP6W//W8QSNhFnxFT+ChxLQSOpZO62QuRhQETrF9LoXNkmDrzJbIHEWy/ig== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-editable-input-hsla@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-editable-input-hsla/-/react-color-editable-input-hsla-2.5.4.tgz#3e62e611389e093209dca9d67d5603230bf18a67" + integrity sha512-9sgFpwLbGCetbKCPVYgmnh9Rn4BPoweaIzPc4CO1HXTsZSTMZahZRq8JciSzu8GXEi2V464p5igsKz264aPY0A== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + +"@uiw/react-color-editable-input-rgba@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-editable-input-rgba/-/react-color-editable-input-rgba-2.5.4.tgz#a9a1b05a8a1c34e88f7249b966d4763c6d24f383" + integrity sha512-XHkYO8JnvgzT8+7ci9VSY2GvNs2+V/HLhCZjJpXAqpU8umY2T9ryhpD0uzKdOieLg74817Ny2ESPrdT/uEGr4A== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + +"@uiw/react-color-editable-input@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-editable-input/-/react-color-editable-input-2.5.4.tgz#b1eb4bc703fd6552032ac3e98963a39b54f16721" + integrity sha512-wn++Hjgv16FCarddAj5RbR/AuGzIs+TYoCJS6wZy1X+BkWjdwN81+mHxXBq42ooge77xkj9Uhbqa7uaIYKCuJA== + +"@uiw/react-color-github@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-github/-/react-color-github-2.5.4.tgz#2920271da7c322a3bc71f37aae5d455d92dd05e3" + integrity sha512-WBTHbt8KOj/VoYybWIDRRxwuFrUtlSYFe4/sNanqezjWqeZF7ZB2fjfv0Tx9/pzqCSeRSS7X+Tm8ce49Uo+46g== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-hue@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-hue/-/react-color-hue-2.5.4.tgz#7285eafbe57deb68017f676a6baa1c943997d72a" + integrity sha512-fUbKPbChCcIkJYyLK9+FhJvvuQgCoxwokq4dma3QeDYHXMHoLqOpWrJlagF+vKqzsPd1dFcH8nPLKf0EO+UjKg== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + +"@uiw/react-color-material@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-material/-/react-color-material-2.5.4.tgz#ed1dafeb53a43db786f2ac647f10a12e22c936c8" + integrity sha512-16GrTKI7F+2gdSwmXlD13Oy4GzxgcMybAXmOrGTrmB1n6JuyUTaXW4vZrGpe3BCt9CKb7ryvLIgTaeKDECUrSQ== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + +"@uiw/react-color-name@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-name/-/react-color-name-2.5.4.tgz#5229a54f2d3a77ee5b39259636889f6937dd857a" + integrity sha512-09fHPL3IBktmoNK5wLqRJbJXMWNGJERKaU/TBKaf9CePVJnxdFsX8X/JQ/UYyMUik2lFLv7HDiuJtRJ+Mk4mcg== + dependencies: + colors-named "^1.0.1" + colors-named-hex "^1.0.1" + +"@uiw/react-color-saturation@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-saturation/-/react-color-saturation-2.5.4.tgz#69cbc69e434a27267ebfb2f0767c8990c552857a" + integrity sha512-aMiqmv91jEZfqgW44E/9S4A7t3ScvsaXcqyjX+vi2zT+H0ZmZfNKfeiytppgurAKaot12vZCZhs+Lvzi8TmXEA== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-drag-event-interactive" "2.5.4" + +"@uiw/react-color-shade-slider@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-shade-slider/-/react-color-shade-slider-2.5.4.tgz#d556b4c75b76285ba9bbb56c8fe2de1f3e971179" + integrity sha512-NeEJ/FhT2wbPNbVfuBwliKgd1BtwZIeOgHDfLOn38hAXSPUVe2LoxLcKOYH/YostsbwRqQ+vYFuNE+++49FyFA== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + +"@uiw/react-color-sketch@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-sketch/-/react-color-sketch-2.5.4.tgz#393823eac72535c0c332317dde3e69ba5bfe8d4d" + integrity sha512-A5ZcJtVPFavbeyf2EZ/V+ttfFJnfZyTzzD17rSIQEqtNaQTvmkKWiSIfiL4XsFsxG4LLyoir79eYsy5/5c2zeg== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + +"@uiw/react-color-slider@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-slider/-/react-color-slider-2.5.4.tgz#a1efd88d0782d8014272c8e6f5cdcf5fbaf14117" + integrity sha512-OxQxlTxGuw052/MZKzGwKiIHj8a2PrYWLtUfvswZZiw4Xr1bj+dQUjSAIiz8XI4oKIVHLZU0U9XRRm+NrD7qmw== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + +"@uiw/react-color-swatch@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-swatch/-/react-color-swatch-2.5.4.tgz#e2775c91b544c0e7cc7935df99bbbce8111577c6" + integrity sha512-//eW0MuhgU0fc+v1QQ0gajY+KI/OME3e8uQ0LfcnZu2pjKVnonHJ2k8iMOno1t8vLiHU9GgYukHixqgpLTC61A== + dependencies: + "@uiw/color-convert" "2.5.4" + +"@uiw/react-color-wheel@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color-wheel/-/react-color-wheel-2.5.4.tgz#cbdcc29b9ee904407aa8bc5453f7280ef7c084e3" + integrity sha512-EQ9mBsBkhiCiHaEUagiF6wGIQuoyFc88HU4x4Kk/sQ+VBUxGpxVxMXRvuBeUwLgypbXSbjClSmQs1mtrJ3e1BQ== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-drag-event-interactive" "2.5.4" + +"@uiw/react-color@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-color/-/react-color-2.5.4.tgz#c088344b2313f98a8a265f19e4ea49e6fe3cdac2" + integrity sha512-hRRqXH4ppqoJdHjlf4dBrHcvQ3GLlmCYDd8KPX9yugxKVSUB8CSNFItF2tfUc4WvdwIC43euqN6bznecWWjKBA== + dependencies: + "@uiw/color-convert" "2.5.4" + "@uiw/react-color-alpha" "2.5.4" + "@uiw/react-color-block" "2.5.4" + "@uiw/react-color-chrome" "2.5.4" + "@uiw/react-color-circle" "2.5.4" + "@uiw/react-color-colorful" "2.5.4" + "@uiw/react-color-compact" "2.5.4" + "@uiw/react-color-editable-input" "2.5.4" + "@uiw/react-color-editable-input-hsla" "2.5.4" + "@uiw/react-color-editable-input-rgba" "2.5.4" + "@uiw/react-color-github" "2.5.4" + "@uiw/react-color-hue" "2.5.4" + "@uiw/react-color-material" "2.5.4" + "@uiw/react-color-name" "2.5.4" + "@uiw/react-color-saturation" "2.5.4" + "@uiw/react-color-shade-slider" "2.5.4" + "@uiw/react-color-sketch" "2.5.4" + "@uiw/react-color-slider" "2.5.4" + "@uiw/react-color-swatch" "2.5.4" + "@uiw/react-color-wheel" "2.5.4" + +"@uiw/react-drag-event-interactive@2.5.4": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@uiw/react-drag-event-interactive/-/react-drag-event-interactive-2.5.4.tgz#743a43695f8e98bdaaa05a3b26204274a24aa0d6" + integrity sha512-VEzRKVPp5tuMDntxVsIJ8liJgJ4t3ZIGORHWReAGzt2IBIFxEAxtN7YsDuoxN2G96qBoWgwZptmAUKdUPHhPMQ== "@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== "@vitejs/plugin-react@^4.5.0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.5.0.tgz#ef2bad6be3031af2b2105b7ab2754f710e890a32" - integrity sha512-JuLWaEqypaJmOJPLWwO335Ig6jSgC1FTONCWAxnqcQthLTK/Yc9aH6hr9z/87xciejbQcnP3GnA1FWUSWeXaeg== - dependencies: - "@babel/core" "^7.26.10" - "@babel/plugin-transform-react-jsx-self" "^7.25.9" - "@babel/plugin-transform-react-jsx-source" "^7.25.9" - "@rolldown/pluginutils" "1.0.0-beta.9" + version "4.7.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz#647af4e7bb75ad3add578e762ad984b90f4a24b9" + integrity sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA== + dependencies: + "@babel/core" "^7.28.0" + "@babel/plugin-transform-react-jsx-self" "^7.27.1" + "@babel/plugin-transform-react-jsx-source" "^7.27.1" + "@rolldown/pluginutils" "1.0.0-beta.27" "@types/babel__core" "^7.20.5" react-refresh "^0.17.0" @@ -2490,9 +2674,9 @@ acorn-jsx@^5.3.2: integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn@^8.9.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== ajv@^6.12.4: version "6.12.6" @@ -2521,13 +2705,6 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -2545,15 +2722,7 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== - dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" - -array-buffer-byte-length@^1.0.2: +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== @@ -2562,16 +2731,18 @@ array-buffer-byte-length@^1.0.2: is-array-buffer "^3.0.5" array-includes@^3.1.6, array-includes@^3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" - integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + version "3.1.9" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.9.tgz#1f0ccaa08e90cdbc3eb433210f903ad0f17c3f3a" + integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ== 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" array-union@^2.1.0: version "2.1.0" @@ -2591,14 +2762,14 @@ array.prototype.findlast@^1.2.5: es-shim-unscopables "^1.0.2" array.prototype.flat@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" array.prototype.flatmap@^1.3.3: version "1.3.3" @@ -2621,20 +2792,6 @@ array.prototype.tosorted@^1.1.4: es-errors "^1.3.0" es-shim-unscopables "^1.0.2" -arraybuffer.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" - is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" - arraybuffer.prototype.slice@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" @@ -2648,6 +2805,11 @@ arraybuffer.prototype.slice@^1.0.4: get-intrinsic "^1.2.6" is-array-buffer "^3.0.4" +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2666,12 +2828,12 @@ available-typed-arrays@^1.0.7: possible-typed-array-names "^1.0.0" axios@^1.8.4: - version "1.8.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.4.tgz#78990bb4bc63d2cae072952d374835950a82f447" - integrity sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw== + version "1.11.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.11.0.tgz#c2ec219e35e414c025b2095e8b8280278478fdb6" + integrity sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA== dependencies: follow-redirects "^1.15.6" - form-data "^4.0.0" + form-data "^4.0.4" proxy-from-env "^1.1.0" babel-plugin-macros@^3.1.0: @@ -2693,23 +2855,28 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-arraybuffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== + bin-pack@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bin-pack/-/bin-pack-1.0.2.tgz#c2a014edbf0bed70a3292062ed46577b96120679" integrity sha512-aOk0SxEon5LF9cMxQFViSKb4qccG6rs7XKyMXIb1J8f8LA2acTIWnHdT0IOTe4gYBbqgjdbuTZ5f+UP+vlh4Mw== brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== dependencies: balanced-match "^1.0.0" @@ -2721,12 +2888,12 @@ braces@^3.0.3: fill-range "^7.1.1" browserslist@^4.24.0: - version "4.25.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.0.tgz#986aa9c6d87916885da2b50d8eb577ac8d133b2c" - integrity sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA== + version "4.25.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" + integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== dependencies: - caniuse-lite "^1.0.30001718" - electron-to-chromium "^1.5.160" + caniuse-lite "^1.0.30001726" + electron-to-chromium "^1.5.173" node-releases "^2.0.19" update-browserslist-db "^1.1.3" @@ -2738,18 +2905,7 @@ call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply- es-errors "^1.3.0" function-bind "^1.1.2" -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - -call-bind@^1.0.8: +call-bind@^1.0.7, call-bind@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== @@ -2759,7 +2915,7 @@ call-bind@^1.0.8: get-intrinsic "^1.2.4" set-function-length "^1.2.2" -call-bound@^1.0.2, call-bound@^1.0.3: +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== @@ -2772,25 +2928,16 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -caniuse-lite@^1.0.30001718: - version "1.0.30001720" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz#c138cb6026d362be9d8d7b0e4bcd0183a850edfd" - integrity sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g== +caniuse-lite@^1.0.30001726: + version "1.0.30001731" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz#277c07416ea4613ec564e5b0ffb47e7b60f32e2f" + integrity sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg== ccount@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -2800,9 +2947,9 @@ chalk@^4.0.0: supports-color "^7.1.0" chalk@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" - integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + version "5.5.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.5.0.tgz#67ada1df5ca809dc84c9b819d76418ddcf128428" + integrity sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg== character-entities-html4@^2.0.0: version "2.1.0" @@ -2839,6 +2986,11 @@ character-reference-invalid@^2.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + chroma-js@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-2.4.2.tgz#dffc214ed0c11fa8eefca2c36651d8e57cbfb2b0" @@ -2869,13 +3021,6 @@ clsx@^2.0.0, clsx@^2.1.0, clsx@^2.1.1: resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -2883,11 +3028,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -2906,6 +3046,16 @@ colorette@^2.0.20: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +colors-named-hex@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/colors-named-hex/-/colors-named-hex-1.0.2.tgz#353165cc548ef0fbd770280bf441ec2dfc1bb386" + integrity sha512-k6kq1e1pUCQvSVwIaGFq2l0LrkAPQZWyeuZn1Z8nOiYSEZiKoFj4qx690h2Kd34DFl9Me0gKS6MUwAMBJj8nuA== + +colors-named@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/colors-named/-/colors-named-1.0.2.tgz#362dd6b520c08da8d9a77250174f0d5f2cfc5b81" + integrity sha512-2ANq2r393PV9njYUD66UdfBcxR1slMqRA3QRTWgCx49JoCJ+kOhyfbQYxKJbPZQIhZUcNjVOs5AlyY1WwXec3w== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -2983,16 +3133,7 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cross-spawn@^7.0.3: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -3008,6 +3149,13 @@ css-in-js-utils@^3.1.0: dependencies: hyphenate-style-name "^1.0.3" +css-line-break@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0" + integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w== + dependencies: + utrie "^1.0.2" + css-tree@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" @@ -3029,9 +3177,9 @@ cytoscape-cose-bilkent@^4.1.0: cose-base "^1.0.0" cytoscape@^3.23.0: - version "3.30.2" - resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.30.2.tgz#94149707fb6547a55e3b44f03ffe232706212161" - integrity sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw== + version "3.33.0" + resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.33.0.tgz#c08136096f568d0f9b438406ec722f1a093b4e16" + integrity sha512-2d2EwwhaxLWC8ahkH1PpQwCyu6EY3xDRdcEJXrLTb4fOUtVc+YWQalHU67rFS1a6ngj1fgv9dQLtJxP/KAFZEw== "d3-dispatch@1 - 3": version "3.0.1" @@ -3057,15 +3205,6 @@ d3-force@^3.0.0: resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== -data-view-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - data-view-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" @@ -3075,15 +3214,6 @@ data-view-buffer@^1.0.2: es-errors "^1.3.0" is-data-view "^1.0.2" -data-view-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-data-view "^1.0.1" - data-view-byte-length@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" @@ -3093,15 +3223,6 @@ data-view-byte-length@^1.0.2: es-errors "^1.3.0" is-data-view "^1.0.2" -data-view-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - data-view-byte-offset@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" @@ -3122,16 +3243,21 @@ date-fns@^3.3.1: integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== dependencies: ms "^2.1.3" +decimal.js@^10.4.3: + version "10.6.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + decode-named-character-reference@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" - integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg== + version "1.2.0" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz#25c32ae6dd5e21889549d40f676030e9514cc0ed" + integrity sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q== dependencies: character-entities "^2.0.0" @@ -3149,7 +3275,7 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" -define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: +define-properties@^1.1.3, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -3173,10 +3299,10 @@ detect-browser@5.3.0: resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== -detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== +detect-libc@^2.0.3, detect-libc@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" + integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== detect-node-es@^1.1.0: version "1.1.0" @@ -3219,10 +3345,10 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" -dset@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.3.tgz#c194147f159841148e8e34ca41f638556d9542d2" - integrity sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ== +dset@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248" + integrity sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA== dunder-proto@^1.0.0, dunder-proto@^1.0.1: version "1.0.1" @@ -3233,10 +3359,10 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" -electron-to-chromium@^1.5.160: - version "1.5.161" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.161.tgz#650376bd3be7ff8e581031409fc2d4f150620b12" - integrity sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA== +electron-to-chromium@^1.5.173: + version "1.5.197" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.197.tgz#117f9d1afd82ae84bbfedd168ddcf52e4afb6216" + integrity sha512-m1xWB3g7vJ6asIFz+2pBUbq3uGmfmln1M9SSvBe4QIFWYrRHylP73zL/3nMjDmwz8V+1xAXQDfBd6+HPW0WvDQ== emoji-regex@^10.3.0: version "10.4.0" @@ -3244,17 +3370,17 @@ emoji-regex@^10.3.0: integrity sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw== enhanced-resolve@^5.18.1: - version "5.18.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" - integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg== + version "5.18.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz#9b5f4c5c076b8787c78fe540392ce76a88855b44" + integrity sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" -entities@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" - integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +entities@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694" + integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g== environment@^1.0.0: version "1.1.0" @@ -3275,79 +3401,27 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.3.4" -es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2, es-abstract@^1.23.3: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== - dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - data-view-buffer "^1.0.1" - data-view-byte-length "^1.0.1" - data-view-byte-offset "^1.0.0" - es-define-property "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - hasown "^2.0.2" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" - is-callable "^1.2.7" - is-data-view "^1.0.1" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.2" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.9" - string.prototype.trimend "^1.0.8" - string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.6" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.15" - -es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9: - version "1.23.9" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.9.tgz#5b45994b7de78dada5c1bebf1379646b32b9d606" - integrity sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA== +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0: + version "1.24.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328" + integrity sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg== 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" @@ -3359,21 +3433,24 @@ es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9: 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" @@ -3382,21 +3459,14 @@ es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9: 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" -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - -es-define-property@^1.0.1: +es-define-property@^1.0.0, es-define-property@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== -es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== @@ -3423,30 +3493,14 @@ es-iterator-helpers@^1.2.1: iterator.prototype "^1.1.4" safe-array-concat "^1.1.3" -es-object-atoms@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== - dependencies: - es-errors "^1.3.0" - -es-object-atoms@^1.1.1: +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== dependencies: es-errors "^1.3.0" -es-set-tostringtag@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" - integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== - dependencies: - get-intrinsic "^1.2.4" - has-tostringtag "^1.0.2" - hasown "^2.0.1" - -es-set-tostringtag@^2.1.0: +es-set-tostringtag@^2.0.3, es-set-tostringtag@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== @@ -3456,21 +3510,12 @@ es-set-tostringtag@^2.1.0: has-tostringtag "^1.0.2" hasown "^2.0.2" -es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== - dependencies: - hasown "^2.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== +es-shim-unscopables@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" + integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" + hasown "^2.0.2" es-to-primitive@^1.3.0: version "1.3.0" @@ -3514,11 +3559,6 @@ escalade@^3.2.0: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -3530,14 +3570,14 @@ escape-string-regexp@^5.0.0: integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== eslint-config-prettier@^10.1.1: - version "10.1.1" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz#cf0ff6e5c4e7e15f129f1f1ce2a5ecba92dec132" - integrity sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw== + version "10.1.8" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97" + integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== eslint-plugin-react-hooks@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz#3d34e37d5770866c34b87d5b499f5f0b53bf0854" - integrity sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw== + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3" + integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg== eslint-plugin-react-refresh@^0.4.20: version "0.4.20" @@ -3545,9 +3585,9 @@ eslint-plugin-react-refresh@^0.4.20: integrity sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA== eslint-plugin-react@^7.37.4: - version "7.37.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz#1b6c80b6175b6ae4b26055ae4d55d04c414c7181" - integrity sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ== + version "7.37.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" + integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== dependencies: array-includes "^3.1.8" array.prototype.findlast "^1.2.5" @@ -3559,7 +3599,7 @@ eslint-plugin-react@^7.37.4: hasown "^2.0.2" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.8" + object.entries "^1.1.9" object.fromentries "^2.0.8" object.values "^1.2.1" prop-types "^15.8.1" @@ -3576,21 +3616,21 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.45.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" "@ungap/structured-clone" "^1.2.0" @@ -3688,21 +3728,28 @@ extend@^3.0.0: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +eyedropper-polyfill@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/eyedropper-polyfill/-/eyedropper-polyfill-1.0.2.tgz#8e6d6e1a872c292e1ea4c474c97b83256447309c" + integrity sha512-tQWOOIxjQpn79Jd03gHyqd8HwDof03LGDiYzwHfLI345/L9XUb5ze3vC0RMYoQhuoslgP5evs1tYN5cl7fwiHw== + dependencies: + html2canvas "^1.4.1" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.2.9: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-json-stable-stringify@^2.0.0: version "2.1.0" @@ -3725,9 +3772,9 @@ fastest-stable-stringify@^2.0.2: integrity sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q== fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== dependencies: reusify "^1.0.4" @@ -3789,36 +3836,38 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== focus-lock@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-1.3.5.tgz#aa644576e5ec47d227b57eb14e1efb2abf33914c" - integrity sha512-QFaHbhv9WPUeLYBDe/PAuLKJ4Dd9OPvKs9xZBr3yLXnUrDNaVXKu2baDBXe3naPY30hgHYSsf2JW4jzas2mDEQ== + version "1.3.6" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-1.3.6.tgz#955eec1e10591d56f679258edb94aedb11d691cd" + integrity sha512-Ik/6OCk9RQQ0T5Xw+hKNLWrjSMtv51dD4GRmJjbD5a58TIEpI5a5iXagKVl3Z5UuyslMCA8Xwnu76jQob62Yhg== dependencies: tslib "^2.0.3" follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== dependencies: - is-callable "^1.1.3" + is-callable "^1.2.7" -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== +form-data@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" mime-types "^2.1.12" format@^0.2.0: @@ -3841,17 +3890,7 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -function.prototype.name@^1.1.8: +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== @@ -3878,18 +3917,7 @@ get-east-asian-width@^1.0.0: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz#21b4071ee58ed04ee0db653371b55b4299875389" integrity sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== @@ -3918,15 +3946,6 @@ get-stream@^8.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== -get-symbol-description@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== - dependencies: - call-bind "^1.0.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - get-symbol-description@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" @@ -3967,11 +3986,6 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - globals@^13.19.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" @@ -3979,7 +3993,7 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globalthis@^1.0.3, globalthis@^1.0.4: +globalthis@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== @@ -4025,14 +4039,7 @@ glsl-tokenizer@^2.0.2: dependencies: through2 "^0.6.3" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -gopd@^1.2.0: +gopd@^1.0.1, gopd@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== @@ -4054,15 +4061,10 @@ graphlib@2.1.8, graphlib@^2.1.8: dependencies: lodash "^4.17.15" -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== has-flag@^4.0.0: version "4.0.0" @@ -4076,11 +4078,6 @@ has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1, has-proto@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== - has-proto@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" @@ -4088,24 +4085,19 @@ has-proto@^1.2.0: dependencies: dunder-proto "^1.0.0" -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-symbols@^1.1.0: +has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: +has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" -hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: +hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -4158,9 +4150,9 @@ hast-util-raw@^9.0.0: zwitch "^2.0.0" hast-util-to-jsx-runtime@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz#3ed27caf8dc175080117706bf7269404a0aa4f7c" - integrity sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ== + version "2.3.6" + resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz#ff31897aae59f62232e21594eac7ef6b63333e98" + integrity sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg== dependencies: "@types/estree" "^1.0.0" "@types/hast" "^3.0.0" @@ -4172,9 +4164,9 @@ hast-util-to-jsx-runtime@^2.0.0: mdast-util-mdx-expression "^2.0.0" mdast-util-mdx-jsx "^3.0.0" mdast-util-mdxjs-esm "^2.0.0" - property-information "^6.0.0" + property-information "^7.0.0" space-separated-tokens "^2.0.0" - style-to-object "^1.0.0" + style-to-js "^1.0.0" unist-util-position "^5.0.0" vfile-message "^4.0.0" @@ -4233,15 +4225,23 @@ hoist-non-react-statics@^3.3.1: react-is "^16.7.0" html-url-attributes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.0.tgz#fc4abf0c3fb437e2329c678b80abb3c62cff6f08" - integrity sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow== + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.1.tgz#83b052cd5e437071b756cd74ae70f708870c2d87" + integrity sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ== html-void-elements@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-3.0.0.tgz#fc9dbd84af9e747249034d4d62602def6517f1d7" integrity sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg== +html2canvas@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543" + integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA== + dependencies: + css-line-break "^2.1.0" + text-segmentation "^1.0.3" + human-signals@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" @@ -4257,15 +4257,15 @@ hyphenate-style-name@^1.0.3: resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz#1797bf50369588b47b72ca6d5e65374607cf4436" integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw== -ignore@^5.2.0, ignore@^5.2.4: - version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -4288,10 +4288,10 @@ inherits@2, inherits@^2.0.4, inherits@~2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inline-style-parser@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.3.tgz#e35c5fb45f3a83ed7849fe487336eb7efa25971c" - integrity sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g== +inline-style-parser@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.4.tgz#f4af5fe72e612839fcd453d989a586566d695f22" + integrity sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q== inline-style-prefixer@^7.0.1: version "7.0.1" @@ -4300,15 +4300,6 @@ inline-style-prefixer@^7.0.1: dependencies: css-in-js-utils "^3.1.0" -internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - internal-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" @@ -4319,14 +4310,14 @@ internal-slot@^1.1.0: side-channel "^1.1.0" intl-messageformat@^10.1.0: - version "10.5.14" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.14.tgz#e5bb373f8a37b88fbe647d7b941f3ab2a37ed00a" - integrity sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w== + version "10.7.16" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.16.tgz#d909f9f9f4ab857fbe681d559b958dd4dd9f665a" + integrity sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug== dependencies: - "@formatjs/ecma402-abstract" "2.0.0" - "@formatjs/fast-memoize" "2.2.0" - "@formatjs/icu-messageformat-parser" "2.7.8" - tslib "^2.4.0" + "@formatjs/ecma402-abstract" "2.3.4" + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/icu-messageformat-parser" "2.11.2" + tslib "^2.8.0" is-alphabetical@^1.0.0: version "1.0.4" @@ -4354,15 +4345,7 @@ is-alphanumerical@^2.0.0: is-alphabetical "^2.0.0" is-decimal "^2.0.0" -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - -is-array-buffer@^3.0.5: +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== @@ -4382,18 +4365,15 @@ is-arrayish@^0.3.1: integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== is-async-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" - integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== - dependencies: - has-tostringtag "^1.0.0" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== dependencies: - has-bigints "^1.0.1" + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" is-bigint@^1.1.0: version "1.1.0" @@ -4402,14 +4382,6 @@ is-bigint@^1.1.0: dependencies: has-bigints "^1.0.2" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-boolean-object@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" @@ -4418,26 +4390,19 @@ is-boolean-object@^1.2.1: call-bound "^1.0.3" has-tostringtag "^1.0.2" -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: +is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.13.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" - integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== - dependencies: - hasown "^2.0.2" - -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== +is-core-module@^2.13.0, is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: - is-typed-array "^1.1.13" + hasown "^2.0.2" -is-data-view@^1.0.2: +is-data-view@^1.0.1, is-data-view@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== @@ -4446,14 +4411,7 @@ is-data-view@^1.0.2: get-intrinsic "^1.2.6" is-typed-array "^1.1.13" -is-date-object@^1.0.1, is-date-object@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-date-object@^1.1.0: +is-date-object@^1.0.5, is-date-object@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== @@ -4496,11 +4454,14 @@ is-fullwidth-code-point@^5.0.0: get-east-asian-width "^1.0.0" is-generator-function@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== dependencies: - has-tostringtag "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" @@ -4529,13 +4490,6 @@ is-negative-zero@^2.0.3: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - is-number-object@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" @@ -4559,14 +4513,6 @@ is-plain-obj@^4.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-regex@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" @@ -4582,13 +4528,6 @@ is-set@^2.0.3: resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== -is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== - dependencies: - call-bind "^1.0.7" - is-shared-array-buffer@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" @@ -4601,13 +4540,6 @@ is-stream@^3.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - is-string@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" @@ -4616,13 +4548,6 @@ is-string@^1.1.1: call-bound "^1.0.3" has-tostringtag "^1.0.2" -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - is-symbol@^1.0.4, is-symbol@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" @@ -4632,14 +4557,7 @@ is-symbol@^1.0.4, is-symbol@^1.1.1: has-symbols "^1.1.0" safe-regex-test "^1.1.0" -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-typed-array@^1.1.14, is-typed-array@^1.1.15: +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: version "1.1.15" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== @@ -4651,14 +4569,7 @@ is-weakmap@^2.0.2: resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -is-weakref@^1.1.0: +is-weakref@^1.0.2, is-weakref@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== @@ -4666,12 +4577,12 @@ is-weakref@^1.1.0: call-bound "^1.0.3" is-weakset@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" - integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" isarray@0.0.1: version "0.0.1" @@ -4701,9 +4612,9 @@ iterator.prototype@^1.1.4: set-function-name "^2.0.2" jiti@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" - integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + version "2.5.1" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.5.1.tgz#bd099c1c2be1c59bbea4e5adcd127363446759d0" + integrity sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w== js-cookie@3.0.1: version "3.0.1" @@ -4727,11 +4638,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - jsesc@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" @@ -4792,73 +4698,73 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lightningcss-darwin-arm64@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.1.tgz#dce17349c7b9f968f396ec240503de14e7b4870b" - integrity sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw== - -lightningcss-darwin-x64@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.1.tgz#e79c984180c57d00ee114210ceced83473d72dfc" - integrity sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA== - -lightningcss-freebsd-x64@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.1.tgz#4b3aec9620684a60c45266d50fd843869320f42f" - integrity sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ== - -lightningcss-linux-arm-gnueabihf@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.1.tgz#b80e9c4dd75652bec451ffd4d5779492a01791ff" - integrity sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg== - -lightningcss-linux-arm64-gnu@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.1.tgz#7825eb119ddf580a4a4f011c6f384a3f9c992060" - integrity sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ== - -lightningcss-linux-arm64-musl@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.1.tgz#389efccf80088dce2bb00e28bd7d1cfe36a71669" - integrity sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw== - -lightningcss-linux-x64-gnu@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.1.tgz#98fc5df5e39ac8ddc51e51f785849eb21131f789" - integrity sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw== - -lightningcss-linux-x64-musl@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.1.tgz#fb4f80895ba7dfa8048ee32e9716a1684fefd6b2" - integrity sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw== - -lightningcss-win32-arm64-msvc@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.1.tgz#fd4409fd1505d89d0ff66511c36df5a1379eb7cd" - integrity sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog== - -lightningcss-win32-x64-msvc@1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.1.tgz#54dcd52884f6cbf205a53d49239559603f194927" - integrity sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q== - -lightningcss@^1.29.1: - version "1.29.1" - resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.29.1.tgz#1d4d62332fc5ba4b6c28e04a8c5638c76019702b" - integrity sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q== - dependencies: - detect-libc "^1.0.3" +lightningcss-darwin-arm64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae" + integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== + +lightningcss-darwin-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" + integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== + +lightningcss-freebsd-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" + integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== + +lightningcss-linux-arm-gnueabihf@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" + integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== + +lightningcss-linux-arm64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" + integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== + +lightningcss-linux-arm64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" + integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== + +lightningcss-linux-x64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" + integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== + +lightningcss-linux-x64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" + integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== + +lightningcss-win32-arm64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" + integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== + +lightningcss-win32-x64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" + integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== + +lightningcss@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.30.1.tgz#78e979c2d595bfcb90d2a8c0eb632fe6c5bfed5d" + integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== + dependencies: + detect-libc "^2.0.3" optionalDependencies: - lightningcss-darwin-arm64 "1.29.1" - lightningcss-darwin-x64 "1.29.1" - lightningcss-freebsd-x64 "1.29.1" - lightningcss-linux-arm-gnueabihf "1.29.1" - lightningcss-linux-arm64-gnu "1.29.1" - lightningcss-linux-arm64-musl "1.29.1" - lightningcss-linux-x64-gnu "1.29.1" - lightningcss-linux-x64-musl "1.29.1" - lightningcss-win32-arm64-msvc "1.29.1" - lightningcss-win32-x64-msvc "1.29.1" + lightningcss-darwin-arm64 "1.30.1" + lightningcss-darwin-x64 "1.30.1" + lightningcss-freebsd-x64 "1.30.1" + lightningcss-linux-arm-gnueabihf "1.30.1" + lightningcss-linux-arm64-gnu "1.30.1" + lightningcss-linux-arm64-musl "1.30.1" + lightningcss-linux-x64-gnu "1.30.1" + lightningcss-linux-x64-musl "1.30.1" + lightningcss-win32-arm64-msvc "1.30.1" + lightningcss-win32-x64-msvc "1.30.1" lilconfig@^3.1.3: version "3.1.3" @@ -4871,9 +4777,9 @@ lines-and-columns@^1.1.6: integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== lint-staged@^15.5.0: - version "15.5.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.5.0.tgz#fa6464cfb06e0faf5bb167f83186e952ff6e569e" - integrity sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg== + version "15.5.2" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.5.2.tgz#beff028fd0681f7db26ffbb67050a21ed4d059a3" + integrity sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w== dependencies: chalk "^5.4.1" commander "^13.1.0" @@ -4887,9 +4793,9 @@ lint-staged@^15.5.0: yaml "^2.7.0" listr2@^8.2.5: - version "8.2.5" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.5.tgz#5c9db996e1afeb05db0448196d3d5f64fec2593d" - integrity sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ== + version "8.3.3" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.3.3.tgz#815fc8f738260ff220981bf9e866b3e11e8121bf" + integrity sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ== dependencies: cli-truncate "^4.0.0" colorette "^2.0.20" @@ -4932,9 +4838,9 @@ log-update@^6.1.0: wrap-ansi "^9.0.0" loglevel@^1.8.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.1.tgz#d63976ac9bcd03c7c873116d41c2a85bafff1be7" - integrity sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg== + version "1.9.2" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.2.tgz#c2e028d6c757720107df4e64508530db6621ba08" + integrity sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg== longest-streak@^3.0.0: version "3.1.0" @@ -4963,6 +4869,13 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +magic-string@^0.30.17: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + markdown-table@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.4.tgz#fe44d6d410ff9d6f2ea1797a3f60aa4d2b631c2a" @@ -4984,9 +4897,9 @@ mdast-util-find-and-replace@^3.0.0: unist-util-visit-parents "^6.0.0" mdast-util-from-markdown@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz#32a6e8f512b416e1f51eb817fc64bd867ebcd9cc" - integrity sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz#4850390ca7cf17413a9b9a0fbefcd1bc0eb4160a" + integrity sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA== dependencies: "@types/mdast" "^4.0.0" "@types/unist" "^3.0.0" @@ -5067,9 +4980,9 @@ mdast-util-gfm@^3.0.0: mdast-util-to-markdown "^2.0.0" mdast-util-mdx-expression@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz#4968b73724d320a379110d853e943a501bfd9d87" - integrity sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz#43f0abac9adc756e2086f63822a38c8d3c3a5096" + integrity sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ== dependencies: "@types/estree-jsx" "^1.0.0" "@types/hast" "^3.0.0" @@ -5079,9 +4992,9 @@ mdast-util-mdx-expression@^2.0.0: mdast-util-to-markdown "^2.0.0" mdast-util-mdx-jsx@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz#daae777c72f9c4a106592e3025aa50fb26068e1b" - integrity sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz#fd04c67a2a7499efb905a8a5c578dddc9fdada0d" + integrity sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q== dependencies: "@types/estree-jsx" "^1.0.0" "@types/hast" "^3.0.0" @@ -5093,7 +5006,6 @@ mdast-util-mdx-jsx@^3.0.0: mdast-util-to-markdown "^2.0.0" parse-entities "^4.0.0" stringify-entities "^4.0.0" - unist-util-remove-position "^5.0.0" unist-util-stringify-position "^4.0.0" vfile-message "^4.0.0" @@ -5133,15 +5045,16 @@ mdast-util-to-hast@^13.0.0: vfile "^6.0.0" mdast-util-to-markdown@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz#9813f1d6e0cdaac7c244ec8c6dabfdb2102ea2b4" - integrity sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ== + version "2.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz#f910ffe60897f04bb4b7e7ee434486f76288361b" + integrity sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA== dependencies: "@types/mdast" "^4.0.0" "@types/unist" "^3.0.0" longest-streak "^3.0.0" mdast-util-phrasing "^4.0.0" mdast-util-to-string "^4.0.0" + micromark-util-classify-character "^2.0.0" micromark-util-decode-string "^2.0.0" unist-util-visit "^5.0.0" zwitch "^2.0.0" @@ -5174,9 +5087,9 @@ merge2@^1.3.0, merge2@^1.4.1: integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromark-core-commonmark@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz#9a45510557d068605c6e9a80f282b2bb8581e43d" - integrity sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA== + version "2.0.3" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz#c691630e485021a68cf28dbc2b2ca27ebf678cd4" + integrity sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg== dependencies: decode-named-character-reference "^1.0.0" devlop "^1.0.0" @@ -5275,18 +5188,18 @@ micromark-extension-gfm@^3.0.0: micromark-util-types "^2.0.0" micromark-factory-destination@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz#857c94debd2c873cba34e0445ab26b74f6a6ec07" - integrity sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz#8fef8e0f7081f0474fbdd92deb50c990a0264639" + integrity sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA== dependencies: micromark-util-character "^2.0.0" micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" micromark-factory-label@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz#17c5c2e66ce39ad6f4fc4cbf40d972f9096f726a" - integrity sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz#5267efa97f1e5254efc7f20b459a38cb21058ba1" + integrity sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg== dependencies: devlop "^1.0.0" micromark-util-character "^2.0.0" @@ -5294,17 +5207,17 @@ micromark-factory-label@^2.0.0: micromark-util-types "^2.0.0" micromark-factory-space@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz#5e7afd5929c23b96566d0e1ae018ae4fcf81d030" - integrity sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz#36d0212e962b2b3121f8525fc7a3c7c029f334fc" + integrity sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg== dependencies: micromark-util-character "^2.0.0" micromark-util-types "^2.0.0" micromark-factory-title@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz#726140fc77892af524705d689e1cf06c8a83ea95" - integrity sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz#237e4aa5d58a95863f01032d9ee9b090f1de6e94" + integrity sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw== dependencies: micromark-factory-space "^2.0.0" micromark-util-character "^2.0.0" @@ -5312,9 +5225,9 @@ micromark-factory-title@^2.0.0: micromark-util-types "^2.0.0" micromark-factory-whitespace@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz#9e92eb0f5468083381f923d9653632b3cfb5f763" - integrity sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz#06b26b2983c4d27bfcc657b33e25134d4868b0b1" + integrity sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ== dependencies: micromark-factory-space "^2.0.0" micromark-util-character "^2.0.0" @@ -5322,48 +5235,48 @@ micromark-factory-whitespace@^2.0.0: micromark-util-types "^2.0.0" micromark-util-character@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.0.tgz#31320ace16b4644316f6bf057531689c71e2aee1" - integrity sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ== + version "2.1.1" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.1.tgz#2f987831a40d4c510ac261e89852c4e9703ccda6" + integrity sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q== dependencies: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" micromark-util-chunked@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz#e51f4db85fb203a79dbfef23fd41b2f03dc2ef89" - integrity sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz#47fbcd93471a3fccab86cff03847fc3552db1051" + integrity sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA== dependencies: micromark-util-symbol "^2.0.0" micromark-util-classify-character@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz#8c7537c20d0750b12df31f86e976d1d951165f34" - integrity sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz#d399faf9c45ca14c8b4be98b1ea481bced87b629" + integrity sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q== dependencies: micromark-util-character "^2.0.0" micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" micromark-util-combine-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz#75d6ab65c58b7403616db8d6b31315013bfb7ee5" - integrity sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz#2a0f490ab08bff5cc2fd5eec6dd0ca04f89b30a9" + integrity sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg== dependencies: micromark-util-chunked "^2.0.0" micromark-util-types "^2.0.0" micromark-util-decode-numeric-character-reference@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz#2698bbb38f2a9ba6310e359f99fcb2b35a0d2bd5" - integrity sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ== + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz#fcf15b660979388e6f118cdb6bf7d79d73d26fe5" + integrity sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw== dependencies: micromark-util-symbol "^2.0.0" micromark-util-decode-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz#7dfa3a63c45aecaa17824e656bcdb01f9737154a" - integrity sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz#6cb99582e5d271e84efca8e61a807994d7161eb2" + integrity sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ== dependencies: decode-named-character-reference "^1.0.0" micromark-util-character "^2.0.0" @@ -5371,42 +5284,42 @@ micromark-util-decode-string@^2.0.0: micromark-util-symbol "^2.0.0" micromark-util-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" - integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz#0d51d1c095551cfaac368326963cf55f15f540b8" + integrity sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw== micromark-util-html-tag-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz#ae34b01cbe063363847670284c6255bb12138ec4" - integrity sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz#e40403096481986b41c106627f98f72d4d10b825" + integrity sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA== micromark-util-normalize-identifier@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz#91f9a4e65fe66cc80c53b35b0254ad67aa431d8b" - integrity sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz#c30d77b2e832acf6526f8bf1aa47bc9c9438c16d" + integrity sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q== dependencies: micromark-util-symbol "^2.0.0" micromark-util-resolve-all@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz#189656e7e1a53d0c86a38a652b284a252389f364" - integrity sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz#e1a2d62cdd237230a2ae11839027b19381e31e8b" + integrity sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg== dependencies: micromark-util-types "^2.0.0" micromark-util-sanitize-uri@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" - integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz#ab89789b818a58752b73d6b55238621b7faa8fd7" + integrity sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ== dependencies: micromark-util-character "^2.0.0" micromark-util-encode "^2.0.0" micromark-util-symbol "^2.0.0" micromark-util-subtokenize@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz#76129c49ac65da6e479c09d0ec4b5f29ec6eace5" - integrity sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q== + version "2.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz#d8ade5ba0f3197a1cf6a2999fbbfe6357a1a19ee" + integrity sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA== dependencies: devlop "^1.0.0" micromark-util-chunked "^2.0.0" @@ -5414,19 +5327,19 @@ micromark-util-subtokenize@^2.0.0: micromark-util-types "^2.0.0" micromark-util-symbol@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" - integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz#e5da494e8eb2b071a0d08fb34f6cefec6c0a19b8" + integrity sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q== micromark-util-types@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" - integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.2.tgz#f00225f5f5a0ebc3254f96c36b6605c4b393908e" + integrity sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA== micromark@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.0.tgz#84746a249ebd904d9658cfabc1e8e5f32cbc6249" - integrity sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ== + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.2.tgz#91395a3e1884a198e62116e33c9c568e39936fdb" + integrity sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA== dependencies: "@types/debug" "^4.0.0" debug "^4.0.0" @@ -5446,7 +5359,7 @@ micromark@^4.0.0: micromark-util-symbol "^2.0.0" micromark-util-types "^2.0.0" -micromatch@^4.0.4, micromatch@^4.0.8: +micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -5490,6 +5403,30 @@ minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minipass@^7.0.4, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.2.tgz#f33d638eb279f664439aa38dc5f91607468cb574" + integrity sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== + dependencies: + minipass "^7.1.2" + +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + mobx@^3.2.2: version "3.6.2" resolved "https://registry.yarnpkg.com/mobx/-/mobx-3.6.2.tgz#fb9f5ff5090539a1ad54e75dc4c098b602693320" @@ -5514,10 +5451,10 @@ nano-css@^5.6.2: stacktrace-js "^2.0.2" stylis "^4.3.0" -nanoid@^3.3.8: - version "3.3.8" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" - integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== natural-compare@^1.4.0: version "1.4.0" @@ -5565,12 +5502,7 @@ object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== - -object-inspect@^1.13.3: +object-inspect@^1.13.3, object-inspect@^1.13.4: version "1.13.4" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== @@ -5580,17 +5512,7 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4, object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.assign@^4.1.7: +object.assign@^4.1.4, object.assign@^4.1.7: version "4.1.7" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== @@ -5602,14 +5524,15 @@ object.assign@^4.1.7: has-symbols "^1.1.0" object-keys "^1.1.1" -object.entries@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" - integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== +object.entries@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.9.tgz#e4770a6a1444afb61bd39f984018b5bede25f8b3" + integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== dependencies: - call-bind "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" define-properties "^1.2.1" - es-object-atoms "^1.0.0" + es-object-atoms "^1.1.1" object.fromentries@^2.0.8: version "2.0.8" @@ -5707,12 +5630,11 @@ parse-entities@^2.0.0: is-hexadecimal "^1.0.0" parse-entities@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.1.tgz#4e2a01111fb1c986549b944af39eeda258fc9e4e" - integrity sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w== + version "4.0.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.2.tgz#61d46f5ed28e4ee62e9ddc43d6b010188443f159" + integrity sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw== dependencies: "@types/unist" "^2.0.0" - character-entities "^2.0.0" character-entities-legacy "^3.0.0" character-reference-invalid "^2.0.0" decode-named-character-reference "^1.0.0" @@ -5731,11 +5653,11 @@ parse-json@^5.0.0: lines-and-columns "^1.1.6" parse5@^7.0.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a" - integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== + version "7.3.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05" + integrity sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw== dependencies: - entities "^4.5.0" + entities "^6.0.0" path-exists@^4.0.0: version "4.0.0" @@ -5767,7 +5689,7 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -picocolors@^1.0.0, picocolors@^1.1.1: +picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== @@ -5788,16 +5710,16 @@ point-in-polygon@^1.1.0: integrity sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw== possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== postcss@^8.4.27, postcss@^8.4.41, postcss@^8.5.3: - version "8.5.3" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" - integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== dependencies: - nanoid "^3.3.8" + nanoid "^3.3.11" picocolors "^1.1.1" source-map-js "^1.2.1" @@ -5807,14 +5729,14 @@ prelude-ls@^1.2.1: integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" - integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== + version "3.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== prismjs@^1.27.0: - version "1.29.0" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" - integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== + version "1.30.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9" + integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== prismjs@~1.27.0: version "1.27.0" @@ -5843,9 +5765,9 @@ property-information@^6.0.0: integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== property-information@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-7.0.0.tgz#3508a6d6b0b8eb3ca6eb2c6623b164d2ed2ab112" - integrity sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg== + version "7.1.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-7.1.0.tgz#b622e8646e02b580205415586b40804d3e8bfd5d" + integrity sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ== proxy-from-env@^1.1.0: version "1.1.0" @@ -5874,12 +5796,7 @@ rbush@^3.0.1: dependencies: quickselect "^2.0.0" -re-resizable@6.10.0: - version "6.10.0" - resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee" - integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw== - -re-resizable@^6.11.2: +re-resizable@6.11.2, re-resizable@^6.11.2: version "6.11.2" resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.11.2.tgz#2e8f7119ca3881d5b5aea0ffa014a80e5c1252b3" integrity sha512-2xI2P3OHs5qw7K0Ud1aLILK6MQxW50TcO+DetD9eIV58j84TqYeHoZcL9H4GXFXXIh7afhH8mv5iUCXII7OW7A== @@ -5929,9 +5846,9 @@ react-aria@3.35.0: "@react-types/shared" "^3.25.0" react-clientside-effect@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz#29f9b14e944a376b03fb650eed2a754dd128ea3a" - integrity sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg== + version "1.2.8" + resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.8.tgz#0b90a9d7b2a1823a3a10ed1ea3f651f7e0301cb7" + integrity sha512-ma2FePH0z3px2+WOu6h+YycZcEvFmmxIlAb62cF52bG86eMySciO/EQZeQMXd07kPCYB0a1dWDT5J+KE9mCDUw== dependencies: "@babel/runtime" "^7.12.13" @@ -5994,10 +5911,10 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== +react-is@^19.0.0: + version "19.1.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.1.1.tgz#038ebe313cf18e1fd1235d51c87360eb87f7c36a" + integrity sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA== react-markdown@^10.1.0: version "10.1.0" @@ -6017,9 +5934,9 @@ react-markdown@^10.1.0: vfile "^6.0.0" react-onclickoutside@^6.13.0: - version "6.13.1" - resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz#1f5e0241c08784b6e65745d91aca0d700c548a89" - integrity sha512-LdrrxK/Yh9zbBQdFbMTXPp3dTSN9B+9YJQucdDu3JNKRrbdU+H+/TVONJoWtOwy4II8Sqf1y/DTI6w/vGPYW0w== + version "6.13.2" + resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.2.tgz#caa6df2c0cfe017506548fa810303fb85d13fb7c" + integrity sha512-h6Hbf1c8b7tIYY4u90mDdBLY4+AGQVMFtIE89HgC0DtVCh/JfKl477gYqUtGLmjZBKK3MJxomP/lFiLbz4sq9A== react-refresh@^0.17.0: version "0.17.0" @@ -6027,19 +5944,19 @@ react-refresh@^0.17.0: integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ== react-router-dom@^6.23.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.26.0.tgz#8debe13295c58605c04f93018d659a763245e58c" - integrity sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ== + version "6.30.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.30.1.tgz#da2580c272ddb61325e435478566be9563a4a237" + integrity sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw== dependencies: - "@remix-run/router" "1.19.0" - react-router "6.26.0" + "@remix-run/router" "1.23.0" + react-router "6.30.1" -react-router@6.26.0, react-router@^6.23.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.26.0.tgz#d5af4c46835b202348ef2b7ddacd32a2db539fde" - integrity sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg== +react-router@6.30.1, react-router@^6.23.1: + version "6.30.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.30.1.tgz#ecb3b883c9ba6dbf5d319ddbc996747f4ab9f4c3" + integrity sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ== dependencies: - "@remix-run/router" "1.19.0" + "@remix-run/router" "1.23.0" react-select@5.9.0: version "5.9.0" @@ -6172,17 +6089,7 @@ refractor@^3.6.0: parse-entities "^2.0.0" prismjs "~1.27.0" -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== - dependencies: - call-bind "^1.0.6" - define-properties "^1.2.1" - es-errors "^1.3.0" - set-function-name "^2.0.1" - -regexp.prototype.flags@^1.5.3: +regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== @@ -6226,9 +6133,9 @@ remark-parse@^11.0.0: unified "^11.0.0" remark-rehype@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.0.tgz#d5f264f42bcbd4d300f030975609d01a1697ccdc" - integrity sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g== + version "11.1.2" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.1.2.tgz#2addaadda80ca9bd9aa0da763e74d16327683b37" + integrity sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw== dependencies: "@types/hast" "^3.0.0" "@types/mdast" "^4.0.0" @@ -6261,11 +6168,11 @@ resolve-from@^4.0.0: integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve@^1.19.0: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== dependencies: - is-core-module "^2.13.0" + is-core-module "^2.16.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -6287,9 +6194,9 @@ restore-cursor@^5.0.0: signal-exit "^4.1.0" reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== rfdc@^1.4.1: version "1.4.1" @@ -6309,9 +6216,9 @@ robust-predicates@^2.0.4: integrity sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg== rollup@^3.27.1: - version "3.29.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" - integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== + version "3.29.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" + integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== optionalDependencies: fsevents "~2.3.2" @@ -6329,16 +6236,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== - dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" - isarray "^2.0.5" - safe-array-concat@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" @@ -6358,15 +6255,6 @@ safe-push-apply@^1.0.0: es-errors "^1.3.0" isarray "^2.0.5" -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - safe-regex-test@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" @@ -6393,12 +6281,12 @@ semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.4: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.5.4, semver@^7.6.0: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== -set-function-length@^1.2.1, set-function-length@^1.2.2: +set-function-length@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== @@ -6410,7 +6298,7 @@ set-function-length@^1.2.1, set-function-length@^1.2.2: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-function-name@^2.0.1, set-function-name@^2.0.2: +set-function-name@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== @@ -6475,16 +6363,6 @@ side-channel-weakmap@^1.0.2: object-inspect "^1.13.3" side-channel-map "^1.0.1" -side-channel@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - side-channel@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" @@ -6593,6 +6471,14 @@ stacktrace-js@^2.0.2: stack-generator "^2.0.5" stacktrace-gps "^3.0.4" +stop-iteration-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== + dependencies: + es-errors "^1.3.0" + internal-slot "^1.1.0" + string-argv@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" @@ -6647,25 +6533,6 @@ string.prototype.trim@^1.2.10: es-object-atoms "^1.0.0" has-property-descriptors "^1.0.2" -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-object-atoms "^1.0.0" - -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - string.prototype.trimend@^1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" @@ -6722,12 +6589,19 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -style-to-object@^1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.6.tgz#0c28aed8be1813d166c60d962719b2907c26547b" - integrity sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA== +style-to-js@^1.0.0: + version "1.1.17" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.17.tgz#488b1558a8c1fd05352943f088cc3ce376813d83" + integrity sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA== + dependencies: + style-to-object "1.0.9" + +style-to-object@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.9.tgz#35c65b713f4a6dba22d3d0c61435f965423653f0" + integrity sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw== dependencies: - inline-style-parser "0.2.3" + inline-style-parser "0.2.4" stylis@4.2.0: version "4.2.0" @@ -6735,16 +6609,9 @@ stylis@4.2.0: integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== stylis@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.2.tgz#8f76b70777dd53eb669c6f58c997bf0a9972e444" - integrity sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" + version "4.3.6" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320" + integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ== supports-color@^7.1.0: version "7.2.0" @@ -6763,20 +6630,34 @@ tabbable@^6.0.0: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== -tailwindcss@4.0.12: - version "4.0.12" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.0.12.tgz#71ab22c78810303b1156354bcc561a747169b5bd" - integrity sha512-bT0hJo91FtncsAMSsMzUkoo/iEU0Xs5xgFgVC9XmdM9bw5MhZuQFjPNl6wxAE0SiQF/YTZJa+PndGWYSDtuxAg== - -tailwindcss@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.5.tgz#d35607f1a351051bd29cda7e59ab2c222ca8deb6" - integrity sha512-nYtSPfWGDiWgCkwQG/m+aX83XCwf62sBgg3bIlNiiOcggnS1x3uVRDAuyelBFL+vJdOPPCGElxv9DjHJjRHiVA== +tailwindcss@4.1.11, tailwindcss@^4.1.5: + version "4.1.11" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.11.tgz#799af3e98c19c5baaefafc6e0c16304a0e684854" + integrity sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA== tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + version "2.2.2" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.2.tgz#ab4984340d30cb9989a490032f086dbb8b56d872" + integrity sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== + +tar@^7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" + integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + +text-segmentation@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943" + integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw== + dependencies: + utrie "^1.0.2" text-table@^0.2.0: version "0.2.0" @@ -6806,11 +6687,6 @@ tinyqueue@^2.0.3: resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08" integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA== -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -6838,22 +6714,17 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.2.0.tgz#94a60bd6bd375c152c1df911a4b11d5b0256f50f" integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw== -ts-api-utils@^1.0.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" - integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== +ts-api-utils@^1.0.1, ts-api-utils@^1.3.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== ts-easing@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.4.1: - version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" - integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== - -tslib@^2.7.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.7.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -6870,15 +6741,6 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - typed-array-buffer@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" @@ -6888,17 +6750,6 @@ typed-array-buffer@^1.0.3: es-errors "^1.3.0" is-typed-array "^1.1.14" -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - typed-array-byte-length@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" @@ -6910,18 +6761,6 @@ typed-array-byte-length@^1.0.3: has-proto "^1.2.0" is-typed-array "^1.1.14" -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - typed-array-byte-offset@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" @@ -6935,18 +6774,6 @@ typed-array-byte-offset@^1.0.4: is-typed-array "^1.1.15" reflect.getprototypeof "^1.0.9" -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - typed-array-length@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" @@ -6960,19 +6787,9 @@ typed-array-length@^1.0.7: reflect.getprototypeof "^1.0.6" typescript@^5.7.3: - version "5.7.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e" - integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw== - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" + version "5.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6" + integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== unbox-primitive@^1.1.0: version "1.1.0" @@ -6984,10 +6801,10 @@ unbox-primitive@^1.1.0: has-symbols "^1.1.0" which-boxed-primitive "^1.1.1" -undici-types@~6.20.0: - version "6.20.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" - integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== unfetch@^3.1.1: version "3.1.2" @@ -7026,14 +6843,6 @@ unist-util-position@^5.0.0: dependencies: "@types/unist" "^3.0.0" -unist-util-remove-position@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" - integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== - dependencies: - "@types/unist" "^3.0.0" - unist-util-visit "^5.0.0" - unist-util-stringify-position@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2" @@ -7074,21 +6883,21 @@ uri-js@^4.2.2: punycode "^2.1.0" use-callback-ref@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.2.tgz#6134c7f6ff76e2be0b56c809b17a650c942b1693" - integrity sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA== + version "1.3.3" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf" + integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg== dependencies: tslib "^2.0.0" use-isomorphic-layout-effect@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz#afb292eb284c39219e8cb8d3d62d71999361a21d" - integrity sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w== + version "1.2.1" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz#2f11a525628f56424521c748feabc2ffcc962fce" + integrity sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA== use-sidecar@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" - integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb" + integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ== dependencies: detect-node-es "^1.1.0" tslib "^2.0.0" @@ -7100,6 +6909,13 @@ usehooks-ts@3.1.0: dependencies: lodash.debounce "^4.0.8" +utrie@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645" + integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw== + dependencies: + base64-arraybuffer "^1.0.2" + uuid@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" @@ -7119,26 +6935,25 @@ vfile-location@^5.0.0: vfile "^6.0.0" vfile-message@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181" - integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw== + version "4.0.3" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.3.tgz#87b44dddd7b70f0641c2e3ed0864ba73e2ea8df4" + integrity sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw== dependencies: "@types/unist" "^3.0.0" unist-util-stringify-position "^4.0.0" vfile@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.2.tgz#ef49548ea3d270097a67011921411130ceae7deb" - integrity sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg== + version "6.0.3" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.3.tgz#3652ab1c496531852bf55a6bac57af981ebc38ab" + integrity sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q== dependencies: "@types/unist" "^3.0.0" - unist-util-stringify-position "^4.0.0" vfile-message "^4.0.0" vite@^4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.3.tgz#d88a4529ea58bae97294c7e2e6f0eab39a50fb1a" - integrity sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg== + version "4.5.14" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.14.tgz#2e652bc1d898265d987d6543ce866ecd65fa4086" + integrity sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g== dependencies: esbuild "^0.18.10" postcss "^8.4.27" @@ -7164,17 +6979,6 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" @@ -7215,26 +7019,16 @@ which-collection@^1.0.2: is-weakmap "^2.0.2" is-weakset "^2.0.3" -which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - -which-typed-array@^1.1.16, which-typed-array@^1.1.18: - version "1.1.18" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" - integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== +which-typed-array@^1.1.16, which-typed-array@^1.1.19: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== dependencies: available-typed-arrays "^1.0.7" call-bind "^1.0.8" - call-bound "^1.0.3" - for-each "^0.3.3" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" gopd "^1.2.0" has-tostringtag "^1.0.2" @@ -7274,15 +7068,20 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + yaml@^1.10.0: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yaml@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98" - integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== yocto-queue@^0.1.0: version "0.1.0" diff --git a/mcp-script/README.md b/mcp-script/README.md new file mode 100644 index 000000000..e0580e227 --- /dev/null +++ b/mcp-script/README.md @@ -0,0 +1,111 @@ +# MCP Neo4j Integration Test Script + +This folder contains a standalone script to test the Model Context Protocol (MCP) integration with Neo4j. + +## ๐Ÿš€ Quick Start + +### 1. Install Dependencies + +```bash +cd mcp-script +pip install -r requirements.txt +``` + +### 2. Configure Environment + +Copy the example environment file and fill in your credentials: + +```bash +cp env_example.txt .env +``` + +Edit `.env` and add your actual values: + +- `NEO4J_PASSWORD`: Your Neo4j database password +- `OPENAI_API_KEY`: Your OpenAI API key + +### 3. Run the Test + +```bash +python test_mcp_neo4j.py +``` + +## ๐Ÿ“ Files + +- `test_mcp_neo4j.py` - Main test script +- `config.py` - Configuration management +- `requirements.txt` - Python dependencies +- `env_example.txt` - Environment variables template +- `README.md` - This file + +## ๐Ÿงช What the Test Does + +The script will: + +1. **Validate Configuration** - Check that all required credentials are provided +2. **Initialize MCP Server** - Connect to Neo4j via MCP protocol +3. **Test Database Connection** - Verify the connection works +4. **Get Database Schema** - Retrieve node labels, relationship types, and properties +5. **Run Test Queries** - Execute several natural language queries: + - Count nodes in database + - List entity types + - Show all documents + - Find Bill Gates connections + - List all relationships + +## ๐Ÿ”ง Configuration + +The script uses these environment variables: + +### Neo4j Configuration + +- `NEO4J_URI` - Neo4j connection URI +- `NEO4J_USERNAME` - Database username +- `NEO4J_PASSWORD` - Database password +- `NEO4J_DATABASE` - Database name + +### OpenAI Configuration + +- `OPENAI_API_KEY` - Your OpenAI API key +- `OPENAI_MODEL` - Model to use (default: gpt-4) +- `OPENAI_TEMPERATURE` - Response randomness (default: 0.1) + +## ๐Ÿ“Š Expected Output + +The script will display: + +- Configuration validation status +- Database connection status +- Database schema information +- Results for each test query +- Success/failure status for each operation + +## ๐Ÿ› Troubleshooting + +### Common Issues + +1. **Import Error**: Make sure you've installed `mcp-neo4j-cypher` + + ```bash + pip install mcp-neo4j-cypher + ``` + +2. **Configuration Error**: Ensure your `.env` file has all required values + +3. **Connection Error**: Verify your Neo4j credentials and network access + +4. **OpenAI Error**: Check your API key and billing status + +### Debug Mode + +For more detailed logging, modify the logging level in `test_mcp_neo4j.py`: + +```python +logging.basicConfig(level=logging.DEBUG) +``` + +## ๐Ÿ”— Related Links + +- [MCP Neo4j Cypher Server](https://github.com/neo4j-contrib/mcp-neo4j/tree/main/servers/mcp-neo4j-cypher) +- [Neo4j MCP Documentation](https://neo4j.com/developer/genai-ecosystem/model-context-protocol-mcp/) +- [Claude + Neo4j via MCP](https://neo4j.com/blog/developer/claude-converses-neo4j-via-mcp/) diff --git a/mcp-script/config.py b/mcp-script/config.py new file mode 100644 index 000000000..f258c2a38 --- /dev/null +++ b/mcp-script/config.py @@ -0,0 +1,44 @@ +""" +Configuration file for MCP Neo4j testing script +""" +import os +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +# Neo4j Database Configuration +NEO4J_CONFIG = { + "uri": os.getenv("NEO4J_URI", "neo4j+s://9379df68.databases.neo4j.io:7687"), + "username": os.getenv("NEO4J_USERNAME", "neo4j"), + "password": os.getenv("NEO4J_PASSWORD", None), # Set this in .env file + "database": os.getenv("NEO4J_DATABASE", "neo4j") +} + +# OpenAI Configuration +OPENAI_CONFIG = { + "api_key": os.getenv("OPENAI_API_KEY", None), # Set this in .env file + "model": os.getenv("OPENAI_MODEL", "gpt-4"), + "temperature": float(os.getenv("OPENAI_TEMPERATURE", "0.1")) +} + +# MCP Configuration +MCP_CONFIG = { + "server_name": "neo4j-cypher", + "timeout": 30 +} + +def validate_config(): + """Validate that required configuration is present""" + errors = [] + + if not NEO4J_CONFIG["password"]: + errors.append("NEO4J_PASSWORD is required") + + if not OPENAI_CONFIG["api_key"]: + errors.append("OPENAI_API_KEY is required") + + if errors: + raise ValueError(f"Configuration errors: {', '.join(errors)}") + + return True diff --git a/mcp-script/env_example.txt b/mcp-script/env_example.txt new file mode 100644 index 000000000..023acf4cd --- /dev/null +++ b/mcp-script/env_example.txt @@ -0,0 +1,12 @@ +# Copy this to .env and fill in your actual values + +# Neo4j Database Configuration +NEO4J_URI=neo4j+s://9379df68.databases.neo4j.io:7687 +NEO4J_USERNAME=neo4j +NEO4J_PASSWORD=your_neo4j_password_here +NEO4J_DATABASE=neo4j + +# OpenAI Configuration +OPENAI_API_KEY=your_openai_api_key_here +OPENAI_MODEL=gpt-4 +OPENAI_TEMPERATURE=0.1 diff --git a/mcp-script/requirements.txt b/mcp-script/requirements.txt new file mode 100644 index 000000000..c386577f3 --- /dev/null +++ b/mcp-script/requirements.txt @@ -0,0 +1,7 @@ +# MCP Neo4j Integration Requirements +mcp-neo4j-cypher>=0.3.1 +openai>=1.0.0 +python-dotenv>=1.0.0 +neo4j>=5.0.0 +mcp>=1.0.0 +httpx>=0.25.0 diff --git a/mcp-script/test_mcp_neo4j.py b/mcp-script/test_mcp_neo4j.py new file mode 100644 index 000000000..ee4269b02 --- /dev/null +++ b/mcp-script/test_mcp_neo4j.py @@ -0,0 +1,576 @@ +#!/usr/bin/env python3 +""" +Standalone MCP Neo4j Integration Test Script + +This script tests the MCP Neo4j integration by: +1. Starting the MCP Neo4j server as a subprocess +2. Connecting to it via HTTP transport +3. Executing natural language queries +4. Displaying results in a structured format + +Usage: + python test_mcp_neo4j.py +""" + +import asyncio +import json +import logging +import sys +import subprocess +import time +import httpx +from typing import Dict, Any, List +import openai +from config import NEO4J_CONFIG, OPENAI_CONFIG, MCP_CONFIG, validate_config +# Import templates from the backend constants +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'backend', 'src')) + +from constants.chart_prompts import create_cypher_query_prompt, create_chart_formatting_prompt + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +class MCPNeo4jTester: + """Test class for MCP Neo4j integration""" + + def __init__(self): + """Initialize the MCP Neo4j tester""" + self.neo4j_config = NEO4J_CONFIG + self.openai_config = OPENAI_CONFIG + self.mcp_config = MCP_CONFIG + + # Initialize OpenAI client + self.openai_client = openai.OpenAI( + api_key=self.openai_config["api_key"] + ) + + # MCP server process and HTTP client + self.mcp_process = None + self.http_client = None + self.server_url = "http://localhost:8001/api/mcp/" + + async def start_mcp_server(self): + """Start the MCP Neo4j server as a subprocess""" + try: + # Set environment variables for the MCP server + env = { + "NEO4J_URI": self.neo4j_config["uri"], + "NEO4J_USERNAME": self.neo4j_config["username"], + "NEO4J_PASSWORD": self.neo4j_config["password"], + "NEO4J_DATABASE": self.neo4j_config["database"], + "NEO4J_TRANSPORT": "http", + "NEO4J_MCP_SERVER_HOST": "127.0.0.1", + "NEO4J_MCP_SERVER_PORT": "8001", + "NEO4J_MCP_SERVER_PATH": "/api/mcp/" + } + + # Start the MCP server process with command line arguments + cmd = [ + "mcp-neo4j-cypher", + "--transport", "http", + "--server-host", "127.0.0.1", + "--server-port", "8001", + "--server-path", "/api/mcp/", + "--db-url", self.neo4j_config["uri"], + "--username", self.neo4j_config["username"], + "--password", self.neo4j_config["password"], + "--database", self.neo4j_config["database"] + ] + + logger.info(f"Starting MCP server with command: {' '.join(cmd)}") + + self.mcp_process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + + # Wait for server to start + await asyncio.sleep(3) + + # Check if process is still running + if self.mcp_process.poll() is not None: + stdout, stderr = self.mcp_process.communicate() + logger.error(f"โŒ MCP server process exited early. stdout: {stdout.decode()}, stderr: {stderr.decode()}") + return False + + # Initialize HTTP client + self.http_client = httpx.AsyncClient(timeout=30.0) + + logger.info("โœ… MCP Neo4j server started successfully") + return True + + except Exception as e: + logger.error(f"โŒ Failed to start MCP server: {e}") + return False + + async def stop_mcp_server(self): + """Stop the MCP server process""" + if self.mcp_process: + self.mcp_process.terminate() + self.mcp_process.wait() + logger.info("โœ… MCP Neo4j server stopped") + + if self.http_client: + await self.http_client.aclose() + + def _parse_sse_response(self, sse_text: str) -> Dict[str, Any]: + """Parse Server-Sent Events response format""" + try: + lines = sse_text.strip().split('\n') + data_line = None + + for line in lines: + if line.startswith('data: '): + data_line = line[6:] # Remove 'data: ' prefix + break + + if data_line: + return json.loads(data_line) + else: + logger.error("No data line found in SSE response") + return None + + except Exception as e: + logger.error(f"Error parsing SSE response: {e}") + return None + + async def test_database_connection(self): + """Test basic database connection via MCP server""" + try: + if not self.http_client: + logger.error("HTTP client not initialized") + return False + + # Test connection with a simple query using MCP + mcp_request = { + "jsonrpc": "2.0", + "id": 1, + "method": "tools/call", + "params": { + "name": "read_neo4j_cypher", + "arguments": { + "query": "RETURN 1 as test" + } + } + } + + response = await self.http_client.post( + self.server_url, + json=mcp_request, + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream" + } + ) + + logger.info(f"Response status: {response.status_code}") + logger.info(f"Response text: {response.text}") + + if response.status_code == 200: + try: + # Parse SSE format response + result = self._parse_sse_response(response.text) + logger.info(f"Parsed result: {result}") + if result and "result" in result: + logger.info("โœ… Database connection successful") + return True + elif result and "error" in result: + logger.error(f"โŒ MCP error: {result['error']}") + return False + except Exception as e: + logger.error(f"โŒ Parse error: {e}") + logger.error(f"Raw response: {response.text}") + return False + + logger.error(f"โŒ Database connection failed: {response.text}") + return False + + except Exception as e: + logger.error(f"โŒ Database connection error: {e}") + return False + + async def get_database_schema(self): + """Get database schema information via MCP""" + try: + if not self.http_client: + return None + + # Get schema using MCP tool + mcp_request = { + "jsonrpc": "2.0", + "id": 2, + "method": "tools/call", + "params": { + "name": "get_neo4j_schema", + "arguments": {} + } + } + + response = await self.http_client.post( + self.server_url, + json=mcp_request, + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream" + } + ) + + if response.status_code == 200: + result = self._parse_sse_response(response.text) + if result and "result" in result: + schema = result["result"]["content"][0]["text"] + logger.info("โœ… Database schema retrieved") + return json.loads(schema) + + logger.error(f"โŒ Failed to get database schema: {response.text}") + return None + + except Exception as e: + logger.error(f"โŒ Failed to get database schema: {e}") + return None + + async def execute_natural_language_query(self, query: str) -> Dict[str, Any]: + """Execute a natural language query using MCP and OpenAI""" + try: + if not self.http_client: + raise Exception("HTTP client not initialized") + + # Get database schema for context + schema = await self.get_database_schema() + + # Create prompt for OpenAI + prompt = create_cypher_query_prompt(query, schema) + + # Call OpenAI to generate Cypher query + response = self.openai_client.chat.completions.create( + model=self.openai_config["model"], + messages=[ + { + "role": "system", + "content": "You are a Neo4j Cypher query expert. Generate accurate Cypher queries based on the database schema and user questions." + }, + { + "role": "user", + "content": prompt + } + ], + temperature=self.openai_config["temperature"], + max_tokens=1000 + ) + + # Extract Cypher query from response + cypher_query = response.choices[0].message.content.strip() + + # Clean up the query (remove markdown formatting if present) + if cypher_query.startswith("```cypher"): + cypher_query = cypher_query[9:] + if cypher_query.startswith("```"): + cypher_query = cypher_query[3:] + if cypher_query.endswith("```"): + cypher_query = cypher_query[:-3] + + cypher_query = cypher_query.strip() + + logger.info(f"Generated Cypher query: {cypher_query}") + + # Execute the query via MCP + mcp_request = { + "jsonrpc": "2.0", + "id": 3, + "method": "tools/call", + "params": { + "name": "read_neo4j_cypher", + "arguments": { + "query": cypher_query + } + } + } + + mcp_response = await self.http_client.post( + self.server_url, + json=mcp_request, + headers={ + "Content-Type": "application/json", + "Accept": "application/json, text/event-stream" + } + ) + + if mcp_response.status_code == 200: + mcp_result = self._parse_sse_response(mcp_response.text) + if mcp_result and "result" in mcp_result: + try: + result_data = mcp_result["result"]["content"][0]["text"] + logger.info(f"Result data to parse: {result_data}") + + if result_data and result_data.strip(): + result = json.loads(result_data) + return { + "natural_language_query": query, + "cypher_query": cypher_query, + "result": result, + "success": True + } + else: + logger.error("Empty result data from MCP") + return { + "natural_language_query": query, + "cypher_query": cypher_query, + "result": None, + "error": "Empty result data from MCP server", + "success": False + } + except json.JSONDecodeError as e: + logger.error(f"JSON decode error: {e}") + logger.error(f"Raw result data: {result_data}") + return { + "natural_language_query": query, + "cypher_query": cypher_query, + "result": None, + "error": f"JSON decode error: {e}", + "success": False + } + else: + logger.error(f"No result in MCP response: {mcp_result}") + return { + "natural_language_query": query, + "cypher_query": cypher_query, + "result": None, + "error": f"No result in MCP response: {mcp_result}", + "success": False + } + + return { + "natural_language_query": query, + "cypher_query": cypher_query, + "result": None, + "error": f"MCP request failed: {mcp_response.text}", + "success": False + } + + except Exception as e: + logger.error(f"โŒ Failed to execute natural language query: {e}") + return { + "natural_language_query": query, + "cypher_query": None, + "result": None, + "error": str(e), + "success": False + } + + + async def display_results(self, results: Dict[str, Any]): + """Display query results in a formatted way""" + print("\n" + "="*80) + print("QUERY RESULTS") + print("="*80) + + print(f"Natural Language Query: {results['natural_language_query']}") + print(f"Cypher Query: {results['cypher_query']}") + print(f"Success: {results['success']}") + + if results['success'] and results['result']: + print("\nRaw Neo4j Results:") + print(json.dumps(results['result'], indent=2)) + + # Try to format the results for chart visualization using LLM + try: + formatted_data = await self._format_chart_data_with_llm(results['natural_language_query'], results['result']) + print("\nLLM-Generated Chart Data:") + print(json.dumps(formatted_data, indent=2)) + except Exception as e: + print(f"\nNote: Could not format as chart data: {e}") + # Fallback to simple formatting + try: + formatted_data = self._format_chart_data_simple(results['result']) + print("\nSimple Formatted Chart Data:") + print(json.dumps(formatted_data, indent=2)) + except Exception as e2: + print(f"Fallback formatting also failed: {e2}") + + elif not results['success']: + print(f"\nError: {results.get('error', 'Unknown error')}") + + print("="*80) + + async def _format_chart_data_with_llm(self, query: str, raw_data: List[Dict[str, Any]]) -> Dict[str, Any]: + """Format raw Neo4j data into chart-compatible format using LLM for color generation""" + try: + if not raw_data: + return {"chartData": [], "chartConfig": {}} + + # Create prompt for LLM to format the data with colors + prompt = create_chart_formatting_prompt(query, "bar", raw_data) + + # Call OpenAI to generate formatted chart data with colors + response = self.openai_client.chat.completions.create( + model=self.openai_config["model"], + messages=[ + { + "role": "system", + "content": "You are a data visualization expert. Format data for charts with bright, vibrant colors. Always return valid JSON." + }, + { + "role": "user", + "content": prompt + } + ], + temperature=0.7, # Higher temperature for more creative colors + max_tokens=1000 + ) + + # Extract and parse the JSON response + chart_data_text = response.choices[0].message.content.strip() + + # Clean up the response (remove markdown formatting if present) + if chart_data_text.startswith("```json"): + chart_data_text = chart_data_text[7:] + if chart_data_text.startswith("```"): + chart_data_text = chart_data_text[3:] + if chart_data_text.endswith("```"): + chart_data_text = chart_data_text[:-3] + + chart_data_text = chart_data_text.strip() + + # Parse the JSON response + formatted_data = json.loads(chart_data_text) + + return formatted_data + + except Exception as e: + logger.error(f"Error formatting chart data with LLM: {e}") + # Fallback to simple formatting + return self._format_chart_data_simple(raw_data) + + def _format_chart_data_simple(self, raw_data: List[Dict[str, Any]]) -> Dict[str, Any]: + """Format raw Neo4j data into chart-compatible format with random colors""" + if not raw_data: + return {"chartData": [], "chartConfig": {}} + + import random + + def generate_random_color(): + """Generate a random bright color""" + # Generate random RGB values with higher saturation for bright colors + r = random.randint(100, 255) + g = random.randint(100, 255) + b = random.randint(100, 255) + return f"#{r:02x}{g:02x}{b:02x}" + + chart_data = [] + chart_config = {} + + # For pie charts and categorical data, assign colors to unique values + # Find the categorical column (usually the first string column) + categorical_column = None + value_column = None + + if raw_data: + first_record = raw_data[0] + for key, value in first_record.items(): + if isinstance(value, str) and categorical_column is None: + categorical_column = key + elif isinstance(value, (int, float)) and value_column is None: + value_column = key + + # Get unique categories from the categorical column + categories = set() + if categorical_column: + for record in raw_data: + if categorical_column in record: + categories.add(record[categorical_column]) + + # Assign random colors to categories + category_colors = {} + for category in categories: + category_colors[category] = generate_random_color() + + # Create chart data + for record in raw_data: + formatted_record = {} + for key, value in record.items(): + formatted_record[key] = value + chart_data.append(formatted_record) + + # Create chart config with proper color assignment + if categorical_column and categories: + # For categorical data, assign colors to each category value + for category in categories: + chart_config[str(category)] = { + "label": str(category).replace("_", " ").title(), + "color": category_colors[category] + } + else: + # Fallback: assign random colors to columns + for i, key in enumerate(first_record.keys()): + chart_config[key] = { + "label": key.replace("_", " ").title(), + "color": generate_random_color() + } + + return { + "chartData": chart_data, + "chartConfig": chart_config + } + +async def main(): + """Main function to run the MCP Neo4j test""" + print("๐Ÿš€ Starting MCP Neo4j Integration Test") + #print("="*50) + + try: + # Validate configuration + validate_config() + logger.info("โœ… Configuration validated") + + # Initialize tester + tester = MCPNeo4jTester() + + # Start MCP server + if not await tester.start_mcp_server(): + sys.exit(1) + + try: + # Test database connection + if not await tester.test_database_connection(): + sys.exit(1) + + # Get database schema + schema = await tester.get_database_schema() + if schema: + print("\n๐Ÿ“Š Database Schema:") + # print(f"Schema: {json.dumps(schema, indent=2)}") + + # Test queries + test_queries = [ + "show me the number of nodes vs number of relationships in the database in a pie chart" + ] + + # print(f"\n๐Ÿงช Running {len(test_queries)} test queries...") + + for i, query in enumerate(test_queries, 1): + print(f"\n[{i}/{len(test_queries)}] Testing: {query}") + results = await tester.execute_natural_language_query(query) + await tester.display_results(results) + + # Add a small delay between queries + await asyncio.sleep(1) + + print("\nโœ… MCP Neo4j integration test completed!") + + finally: + # Always stop the MCP server + await tester.stop_mcp_server() + + except Exception as e: + logger.error(f"โŒ Test failed: {e}") + sys.exit(1) + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/nrcmvp b/nrcmvp new file mode 160000 index 000000000..6b2140a97 --- /dev/null +++ b/nrcmvp @@ -0,0 +1 @@ +Subproject commit 6b2140a974f367bb58d898c4f303a88c944e2b58 diff --git a/reports.txt b/reports.txt new file mode 100644 index 000000000..f07cac84e --- /dev/null +++ b/reports.txt @@ -0,0 +1,32 @@ +#TO-DO: Refine user input using LLM before sending to MCP + + + +You are a helpful assistant that works with Neo4j databases. You can help with schema discovery, running Cypher queries, and data manipulation. + +User requirement: show me the number of nodes vs number of relationships in the database in a pie chart + +Given the user requirement assume that you have access to recharts react library,return a json object that would be used for data visualization. It should include the chartConfig and the chartData in a single object. + +Feel free to pick appropriate colors and labels for your chartConfig. + +e.g of a response: +{ + chartConfig: { + desktop: { + label: "Desktop", + color: "#2563eb", + }, + mobile: { + label: "Mobile", + color: "#60a5fa", + }, + }, + chartData: [ + { month: "January", desktop: 186, mobile: 80 }, + { month: "February", desktop: 305, mobile: 200 }, + { month: "March", desktop: 237, mobile: 120 }, + { month: "April", desktop: 73, mobile: 190 }, + { month: "May", desktop: 209, mobile: 130 }, + { month: "June", desktop: 214, mobile: 140 },] +}