diff --git a/Makefile b/Makefile index 7ffb5dd..1db2066 100644 --- a/Makefile +++ b/Makefile @@ -59,9 +59,15 @@ grpcui: ## Open gRPC UI in browser @echo "Opening gRPC UI at http://localhost:8081" @open http://localhost:8081 2>/dev/null || xdg-open http://localhost:8081 2>/dev/null || echo "Open http://localhost:8081 in your browser" -db: ## Open SQLite Web browser - @echo "Opening SQLite Web at http://localhost:8082" - @open http://localhost:8082 2>/dev/null || xdg-open http://localhost:8082 2>/dev/null || echo "Open http://localhost:8082 in your browser" +db: ## Open pgAdmin web interface (starts with --profile tools if needed) + @if ! docker ps --format '{{.Names}}' | grep -q fi-pgadmin; then \ + echo "Starting pgAdmin..."; \ + docker-compose --profile tools up -d pgadmin; \ + sleep 2; \ + fi + @echo "Opening pgAdmin at http://localhost:5050" + @echo "Login: admin@fiapply.local / admin" + @open http://localhost:5050 2>/dev/null || xdg-open http://localhost:5050 2>/dev/null || echo "Open http://localhost:5050 in your browser" # Status status: ## Show status of all services @@ -92,5 +98,12 @@ quickstart: install build up ## Install, build, and start everything @echo "Frontend: http://localhost:3000" @echo "Swagger UI: http://localhost:8080" @echo "gRPC UI: http://localhost:8081" - @echo "DB Browser: http://localhost:8082" + @echo "pgAdmin: http://localhost:5050" @echo "" + +PYTHONPATH := $(shell pwd) + +# Run pytest on the RAG engine tests +test-rag: + @echo "๐Ÿงช Running RAG engine tests..." + PYTHONPATH=$(PYTHONPATH) pytest -s -v --full-trace backend/services/rag_engine/tests/test.py \ No newline at end of file diff --git a/README.md b/README.md index c418762..945d1b2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ FiApply/ โ”œโ”€โ”€ backend/ # Python gRPC microservices โ”œโ”€โ”€ frontend/ # React TypeScript PWA โ”œโ”€โ”€ proto/ # Protocol Buffer definitions -โ”œโ”€โ”€ db/ # SQLite database +โ”œโ”€โ”€ db/ # PostgreSQL database โ””โ”€โ”€ docs/ # Documentation ``` @@ -25,7 +25,7 @@ FiApply/ **Tech Stack:** - **Backend**: Python 3.11+, gRPC, Connect RPC, Playwright, LangChain, LangGraph - **Frontend**: React 18, TypeScript, Vite, ShadCN UI, Redux Toolkit, Connect-Web -- **Database**: SQLite with vector extensions +- **Database**: PostgreSQL 17-alpine3.22 with pgvector, pg_trgm, pg_stat_statements - **AI**: Stagehand (browser automation), Ollama/OpenRouter (LLMs) --- @@ -63,7 +63,7 @@ python backend/services/llm_manager/example_client.py - ๐ŸŽจ **Frontend**: http://localhost:3000 - ๐Ÿ“š **API Docs**: http://localhost:8080 (Swagger UI) - ๐Ÿ”ง **gRPC Testing**: http://localhost:8081 (gRPC UI) -- ๐Ÿ’พ **Database**: http://localhost:8082 (SQLite Web) +- ๐Ÿ’พ **Database**: http://localhost:5050 (pgAdmin) See **[docs/DOCKER.md](docs/DOCKER.md)** for detailed Docker documentation. @@ -285,16 +285,17 @@ All tools run automatically with Docker. | Service | Port | Description | |---------|------|-------------| +| **postgres** | 5432 | PostgreSQL database | +| **pgadmin** | 5050 | Database management UI | | **ollama** | 11434 | Local LLM runtime | | **swagger-ui** | 8080 | API documentation | | **grpcui** | 8081 | Interactive gRPC testing | -| **sqlite-web** | 8082 | Database browser | Access via: ```zsh make swagger # http://localhost:8080 make grpcui # http://localhost:8081 -make db # http://localhost:8082 +make db # http://localhost:5050 (pgAdmin) ``` --- @@ -325,7 +326,7 @@ FiApply/ โ”‚ โ”œโ”€โ”€ ai_orchestrator.proto โ”‚ โ”œโ”€โ”€ rag_engine.proto โ”‚ โ””โ”€โ”€ llm_manager.proto -โ”œโ”€โ”€ db/ # SQLite database +โ”œโ”€โ”€ db/ # PostgreSQL database โ”œโ”€โ”€ docs/ # Documentation โ”œโ”€โ”€ docker-compose.yml # Full stack orchestration โ”œโ”€โ”€ Makefile # Development commands @@ -390,7 +391,11 @@ STAGEHAND_API_KEY=... OPENROUTER_API_KEY=... # Database -DB_PATH=/path/to/production.db +DB_HOST=postgres +DB_PORT=5432 +DB_NAME=fiapply +DB_USER=fiapply_user +DB_PASSWORD=fiapply_password # Service ports (optional) GATEWAY_PORT=50051 @@ -457,8 +462,8 @@ docker-compose exec ai-orchestrator playwright install chromium - โœ… OpenAPI/Swagger documentation - โœ… Browser automation with Stagehand - โœ… Connect RPC (gRPC + HTTP/JSON support) +- โœ… PostgreSQL database with vector search (pgvector) - โณ Service implementations (see TODO comments in code) -- โณ Database schema and migrations - โณ Authentication system - โณ Production deployment configs diff --git a/backend/generated/ai_orchestrator_pb2.py b/backend/generated/ai_orchestrator_pb2.py index 1f32b41..bad9a27 100644 --- a/backend/generated/ai_orchestrator_pb2.py +++ b/backend/generated/ai_orchestrator_pb2.py @@ -22,7 +22,7 @@ _sym_db = _symbol_database.Default() -from backend.generated import common_pb2 as common__pb2 +import common_pb2 as common__pb2 from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 diff --git a/backend/generated/ai_orchestrator_pb2_grpc.py b/backend/generated/ai_orchestrator_pb2_grpc.py index 95c4188..d6fc08d 100644 --- a/backend/generated/ai_orchestrator_pb2_grpc.py +++ b/backend/generated/ai_orchestrator_pb2_grpc.py @@ -2,7 +2,7 @@ """Client and server classes corresponding to protobuf-defined services.""" import grpc -from backend.generated import ai_orchestrator_pb2 as ai__orchestrator__pb2 +import ai_orchestrator_pb2 as ai__orchestrator__pb2 class AIOrchestratorStub(object): diff --git a/backend/generated/api_gateway_pb2.py b/backend/generated/api_gateway_pb2.py index d6fea9e..82dcadd 100644 --- a/backend/generated/api_gateway_pb2.py +++ b/backend/generated/api_gateway_pb2.py @@ -22,8 +22,8 @@ _sym_db = _symbol_database.Default() -from backend.generated import common_pb2 as common__pb2 -from backend.generated import headless_streaming_pb2 as headless__streaming__pb2 +import common_pb2 as common__pb2 +import headless_streaming_pb2 as headless__streaming__pb2 from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 diff --git a/backend/generated/api_gateway_pb2_grpc.py b/backend/generated/api_gateway_pb2_grpc.py index a2867a6..89c9423 100644 --- a/backend/generated/api_gateway_pb2_grpc.py +++ b/backend/generated/api_gateway_pb2_grpc.py @@ -2,9 +2,9 @@ """Client and server classes corresponding to protobuf-defined services.""" import grpc -from backend.generated import api_gateway_pb2 as api__gateway__pb2 +import api_gateway_pb2 as api__gateway__pb2 from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 -from backend.generated import headless_streaming_pb2 as headless__streaming__pb2 +import headless_streaming_pb2 as headless__streaming__pb2 class GatewayStub(object): diff --git a/backend/generated/llm_manager_pb2.py b/backend/generated/llm_manager_pb2.py index 8c00669..60fec1b 100644 --- a/backend/generated/llm_manager_pb2.py +++ b/backend/generated/llm_manager_pb2.py @@ -22,7 +22,7 @@ _sym_db = _symbol_database.Default() -from backend.generated import common_pb2 as common__pb2 +import common_pb2 as common__pb2 from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 diff --git a/backend/generated/llm_manager_pb2_grpc.py b/backend/generated/llm_manager_pb2_grpc.py index a47e2d6..73d54d6 100644 --- a/backend/generated/llm_manager_pb2_grpc.py +++ b/backend/generated/llm_manager_pb2_grpc.py @@ -2,7 +2,7 @@ """Client and server classes corresponding to protobuf-defined services.""" import grpc -from backend.generated import llm_manager_pb2 as llm__manager__pb2 +import llm_manager_pb2 as llm__manager__pb2 class LLMManagerStub(object): diff --git a/backend/generated/rag_engine_pb2.py b/backend/generated/rag_engine_pb2.py index bbc896c..f90dbd1 100644 --- a/backend/generated/rag_engine_pb2.py +++ b/backend/generated/rag_engine_pb2.py @@ -27,7 +27,7 @@ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10rag_engine.proto\x12\tfi.rag.v1\x1a\x0c\x63ommon.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xa5\x01\n\x14StoreDocumentRequest\x12\x1f\n\x0b\x64ocument_id\x18\x01 \x01(\tR\ndocumentId\x12\x18\n\x07\x63ontent\x18\x02 \x01(\tR\x07\x63ontent\x12\x33\n\x08metadata\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\x12\x1d\n\nsource_url\x18\x04 \x01(\tR\tsourceUrl\"\xa2\x01\n\x15StoreDocumentResponse\x12\x1f\n\x0b\x64ocument_id\x18\x01 \x01(\tR\ndocumentId\x12\x18\n\x07success\x18\x02 \x01(\x08R\x07success\x12#\n\rchunks_stored\x18\x03 \x01(\x05R\x0c\x63hunksStored\x12)\n\x05\x65rror\x18\x04 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"{\n\x0fRetrieveRequest\x12\x14\n\x05query\x18\x01 \x01(\tR\x05query\x12\x1f\n\x0bmax_results\x18\x02 \x01(\x05R\nmaxResults\x12\x31\n\x07\x66ilters\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x66ilters\"n\n\x10RetrieveResponse\x12/\n\x06\x63hunks\x18\x01 \x03(\x0b\x32\x17.fi.rag.v1.ContextChunkR\x06\x63hunks\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"\x9e\x01\n\x0c\x43ontextChunk\x12\x18\n\x07\x63ontent\x18\x01 \x01(\tR\x07\x63ontent\x12\'\n\x0frelevance_score\x18\x02 \x01(\x01R\x0erelevanceScore\x12\x33\n\x08metadata\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\x12\x16\n\x06source\x18\x04 \x01(\tR\x06source\"&\n\x10\x45mbeddingRequest\x12\x12\n\x04text\x18\x01 \x01(\tR\x04text\"\\\n\x11\x45mbeddingResponse\x12\x1c\n\tembedding\x18\x01 \x03(\x02R\tembedding\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"n\n\rSearchRequest\x12\x14\n\x05query\x18\x01 \x01(\tR\x05query\x12\x14\n\x05limit\x18\x02 \x01(\x05R\x05limit\x12\x31\n\x07\x66ilters\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x66ilters\"n\n\x0eSearchResponse\x12\x31\n\x07results\x18\x01 \x03(\x0b\x32\x17.fi.rag.v1.SearchResultR\x07results\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"\x94\x01\n\x0cSearchResult\x12\x1f\n\x0b\x64ocument_id\x18\x01 \x01(\tR\ndocumentId\x12\x18\n\x07\x63ontent\x18\x02 \x01(\tR\x07\x63ontent\x12\x14\n\x05score\x18\x03 \x01(\x01R\x05score\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata2\xc2\x02\n\tRAGEngine\x12R\n\rStoreDocument\x12\x1f.fi.rag.v1.StoreDocumentRequest\x1a .fi.rag.v1.StoreDocumentResponse\x12J\n\x0fRetrieveContext\x12\x1a.fi.rag.v1.RetrieveRequest\x1a\x1b.fi.rag.v1.RetrieveResponse\x12N\n\x11GenerateEmbedding\x12\x1b.fi.rag.v1.EmbeddingRequest\x1a\x1c.fi.rag.v1.EmbeddingResponse\x12\x45\n\x0eSemanticSearch\x12\x18.fi.rag.v1.SearchRequest\x1a\x19.fi.rag.v1.SearchResponseB\xa2\x01\n\rcom.fi.rag.v1B\x0eRagEngineProtoP\x01Z;github.com/Firelight-Innovations/FiApply/proto/rag/v1;ragv1\xa2\x02\x03\x46RX\xaa\x02\tFi.Rag.V1\xca\x02\tFi\\Rag\\V1\xe2\x02\x15\x46i\\Rag\\V1\\GPBMetadata\xea\x02\x0b\x46i::Rag::V1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10rag_engine.proto\x12\tfi.rag.v1\x1a\x0c\x63ommon.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xa5\x01\n\x14StoreDocumentRequest\x12\x1f\n\x0b\x64ocument_id\x18\x01 \x01(\tR\ndocumentId\x12\x18\n\x07\x63ontent\x18\x02 \x01(\tR\x07\x63ontent\x12\x33\n\x08metadata\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\x12\x1d\n\nsource_url\x18\x04 \x01(\tR\tsourceUrl\"\xa2\x01\n\x15StoreDocumentResponse\x12\x1f\n\x0b\x64ocument_id\x18\x01 \x01(\tR\ndocumentId\x12\x18\n\x07success\x18\x02 \x01(\x08R\x07success\x12#\n\rchunks_stored\x18\x03 \x01(\x05R\x0c\x63hunksStored\x12)\n\x05\x65rror\x18\x04 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"{\n\x0fRetrieveRequest\x12\x14\n\x05query\x18\x01 \x01(\tR\x05query\x12\x1f\n\x0bmax_results\x18\x02 \x01(\x05R\nmaxResults\x12\x31\n\x07\x66ilters\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x66ilters\"n\n\x10RetrieveResponse\x12/\n\x06\x63hunks\x18\x01 \x03(\x0b\x32\x17.fi.rag.v1.ContextChunkR\x06\x63hunks\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"\x9e\x01\n\x0c\x43ontextChunk\x12\x18\n\x07\x63ontent\x18\x01 \x01(\tR\x07\x63ontent\x12\'\n\x0frelevance_score\x18\x02 \x01(\x01R\x0erelevanceScore\x12\x33\n\x08metadata\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\x12\x16\n\x06source\x18\x04 \x01(\tR\x06source\"&\n\x10\x45mbeddingRequest\x12\x12\n\x04text\x18\x01 \x01(\tR\x04text\"\\\n\x11\x45mbeddingResponse\x12\x1c\n\tembedding\x18\x01 \x03(\x02R\tembedding\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"n\n\rSearchRequest\x12\x14\n\x05query\x18\x01 \x01(\tR\x05query\x12\x14\n\x05limit\x18\x02 \x01(\x05R\x05limit\x12\x31\n\x07\x66ilters\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x66ilters\"n\n\x0eSearchResponse\x12\x31\n\x07results\x18\x01 \x03(\x0b\x32\x17.fi.rag.v1.SearchResultR\x07results\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"\x94\x01\n\x0cSearchResult\x12\x1f\n\x0b\x64ocument_id\x18\x01 \x01(\tR\ndocumentId\x12\x18\n\x07\x63ontent\x18\x02 \x01(\tR\x07\x63ontent\x12\x14\n\x05score\x18\x03 \x01(\x01R\x05score\x12\x33\n\x08metadata\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"c\n\x0bInitRequest\x12+\n\x11\x63onnection_string\x18\x01 \x01(\tR\x10\x63onnectionString\x12\'\n\x0f\x63ollection_name\x18\x02 \x01(\tR\x0e\x63ollectionName\"S\n\x0cInitResponse\x12\x18\n\x07success\x18\x01 \x01(\x08R\x07success\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"Z\n\x1c\x45mbedScholarshipBatchRequest\x12:\n\x0cscholarships\x18\x01 \x03(\x0b\x32\x16.fi.rag.v1.ScholarshipR\x0cscholarships\"q\n\x1d\x45mbedScholarshipBatchResponse\x12%\n\x0etotal_embedded\x18\x01 \x01(\x05R\rtotalEmbedded\x12)\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x13.fi.common.v1.ErrorR\x05\x65rror\"z\n\x08\x44ocument\x12\x1f\n\x0b\x64ocument_id\x18\x01 \x01(\tR\ndocumentId\x12\x18\n\x07\x63ontent\x18\x02 \x01(\tR\x07\x63ontent\x12\x33\n\x08metadata\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x08metadata\"\xa3\x02\n\x0bScholarship\x12\x0e\n\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\n\x04name\x18\x02 \x01(\tR\x04name\x12 \n\x0b\x64\x65scription\x18\x03 \x01(\tR\x0b\x64\x65scription\x12\x17\n\x07min_gpa\x18\x04 \x01(\x01R\x06minGpa\x12\'\n\x0f\x65ligible_majors\x18\x05 \x03(\tR\x0e\x65ligibleMajors\x12\x31\n\x14\x63itizenship_required\x18\x06 \x01(\tR\x13\x63itizenshipRequired\x12\x1a\n\x08location\x18\x07 \x01(\tR\x08location\x12!\n\x0c\x61ward_amount\x18\x08 \x01(\tR\x0b\x61wardAmount\x12\x1a\n\x08keywords\x18\t \x03(\tR\x08keywords2\xc2\x02\n\tRAGEngine\x12R\n\rStoreDocument\x12\x1f.fi.rag.v1.StoreDocumentRequest\x1a .fi.rag.v1.StoreDocumentResponse\x12J\n\x0fRetrieveContext\x12\x1a.fi.rag.v1.RetrieveRequest\x1a\x1b.fi.rag.v1.RetrieveResponse\x12N\n\x11GenerateEmbedding\x12\x1b.fi.rag.v1.EmbeddingRequest\x1a\x1c.fi.rag.v1.EmbeddingResponse\x12\x45\n\x0eSemanticSearch\x12\x18.fi.rag.v1.SearchRequest\x1a\x19.fi.rag.v1.SearchResponse2\xb6\x01\n\x0fVectorDBService\x12\x37\n\x04Init\x12\x16.fi.rag.v1.InitRequest\x1a\x17.fi.rag.v1.InitResponse\x12j\n\x15\x45mbedScholarshipBatch\x12\'.fi.rag.v1.EmbedScholarshipBatchRequest\x1a(.fi.rag.v1.EmbedScholarshipBatchResponseB\xa2\x01\n\rcom.fi.rag.v1B\x0eRagEngineProtoP\x01Z;github.com/Firelight-Innovations/FiApply/proto/rag/v1;ragv1\xa2\x02\x03\x46RX\xaa\x02\tFi.Rag.V1\xca\x02\tFi\\Rag\\V1\xe2\x02\x15\x46i\\Rag\\V1\\GPBMetadata\xea\x02\x0b\x46i::Rag::V1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -55,6 +55,20 @@ _globals['_SEARCHRESPONSE']._serialized_end=1191 _globals['_SEARCHRESULT']._serialized_start=1194 _globals['_SEARCHRESULT']._serialized_end=1342 - _globals['_RAGENGINE']._serialized_start=1345 - _globals['_RAGENGINE']._serialized_end=1667 + _globals['_INITREQUEST']._serialized_start=1344 + _globals['_INITREQUEST']._serialized_end=1443 + _globals['_INITRESPONSE']._serialized_start=1445 + _globals['_INITRESPONSE']._serialized_end=1528 + _globals['_EMBEDSCHOLARSHIPBATCHREQUEST']._serialized_start=1530 + _globals['_EMBEDSCHOLARSHIPBATCHREQUEST']._serialized_end=1620 + _globals['_EMBEDSCHOLARSHIPBATCHRESPONSE']._serialized_start=1622 + _globals['_EMBEDSCHOLARSHIPBATCHRESPONSE']._serialized_end=1735 + _globals['_DOCUMENT']._serialized_start=1737 + _globals['_DOCUMENT']._serialized_end=1859 + _globals['_SCHOLARSHIP']._serialized_start=1862 + _globals['_SCHOLARSHIP']._serialized_end=2153 + _globals['_RAGENGINE']._serialized_start=2156 + _globals['_RAGENGINE']._serialized_end=2478 + _globals['_VECTORDBSERVICE']._serialized_start=2481 + _globals['_VECTORDBSERVICE']._serialized_end=2663 # @@protoc_insertion_point(module_scope) diff --git a/backend/generated/rag_engine_pb2.pyi b/backend/generated/rag_engine_pb2.pyi index 9983081..999a07b 100644 --- a/backend/generated/rag_engine_pb2.pyi +++ b/backend/generated/rag_engine_pb2.pyi @@ -106,3 +106,65 @@ class SearchResult(_message.Message): score: float metadata: _struct_pb2.Struct def __init__(self, document_id: _Optional[str] = ..., content: _Optional[str] = ..., score: _Optional[float] = ..., metadata: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ... + +class InitRequest(_message.Message): + __slots__ = ("connection_string", "collection_name") + CONNECTION_STRING_FIELD_NUMBER: _ClassVar[int] + COLLECTION_NAME_FIELD_NUMBER: _ClassVar[int] + connection_string: str + collection_name: str + def __init__(self, connection_string: _Optional[str] = ..., collection_name: _Optional[str] = ...) -> None: ... + +class InitResponse(_message.Message): + __slots__ = ("success", "error") + SUCCESS_FIELD_NUMBER: _ClassVar[int] + ERROR_FIELD_NUMBER: _ClassVar[int] + success: bool + error: _common_pb2.Error + def __init__(self, success: _Optional[bool] = ..., error: _Optional[_Union[_common_pb2.Error, _Mapping]] = ...) -> None: ... + +class EmbedScholarshipBatchRequest(_message.Message): + __slots__ = ("scholarships",) + SCHOLARSHIPS_FIELD_NUMBER: _ClassVar[int] + scholarships: _containers.RepeatedCompositeFieldContainer[Scholarship] + def __init__(self, scholarships: _Optional[_Iterable[_Union[Scholarship, _Mapping]]] = ...) -> None: ... + +class EmbedScholarshipBatchResponse(_message.Message): + __slots__ = ("total_embedded", "error") + TOTAL_EMBEDDED_FIELD_NUMBER: _ClassVar[int] + ERROR_FIELD_NUMBER: _ClassVar[int] + total_embedded: int + error: _common_pb2.Error + def __init__(self, total_embedded: _Optional[int] = ..., error: _Optional[_Union[_common_pb2.Error, _Mapping]] = ...) -> None: ... + +class Document(_message.Message): + __slots__ = ("document_id", "content", "metadata") + DOCUMENT_ID_FIELD_NUMBER: _ClassVar[int] + CONTENT_FIELD_NUMBER: _ClassVar[int] + METADATA_FIELD_NUMBER: _ClassVar[int] + document_id: str + content: str + metadata: _struct_pb2.Struct + def __init__(self, document_id: _Optional[str] = ..., content: _Optional[str] = ..., metadata: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ... + +class Scholarship(_message.Message): + __slots__ = ("id", "name", "description", "min_gpa", "eligible_majors", "citizenship_required", "location", "award_amount", "keywords") + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + DESCRIPTION_FIELD_NUMBER: _ClassVar[int] + MIN_GPA_FIELD_NUMBER: _ClassVar[int] + ELIGIBLE_MAJORS_FIELD_NUMBER: _ClassVar[int] + CITIZENSHIP_REQUIRED_FIELD_NUMBER: _ClassVar[int] + LOCATION_FIELD_NUMBER: _ClassVar[int] + AWARD_AMOUNT_FIELD_NUMBER: _ClassVar[int] + KEYWORDS_FIELD_NUMBER: _ClassVar[int] + id: int + name: str + description: str + min_gpa: float + eligible_majors: _containers.RepeatedScalarFieldContainer[str] + citizenship_required: str + location: str + award_amount: str + keywords: _containers.RepeatedScalarFieldContainer[str] + def __init__(self, id: _Optional[int] = ..., name: _Optional[str] = ..., description: _Optional[str] = ..., min_gpa: _Optional[float] = ..., eligible_majors: _Optional[_Iterable[str]] = ..., citizenship_required: _Optional[str] = ..., location: _Optional[str] = ..., award_amount: _Optional[str] = ..., keywords: _Optional[_Iterable[str]] = ...) -> None: ... diff --git a/backend/generated/rag_engine_pb2_grpc.py b/backend/generated/rag_engine_pb2_grpc.py index 9b90cdf..b1b016a 100644 --- a/backend/generated/rag_engine_pb2_grpc.py +++ b/backend/generated/rag_engine_pb2_grpc.py @@ -211,3 +211,129 @@ def SemanticSearch(request, timeout, metadata, _registered_method=True) + + +class VectorDBServiceStub(object): + """========================================= + VectorDBService - declare RPC methods + ========================================= + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Init = channel.unary_unary( + '/fi.rag.v1.VectorDBService/Init', + request_serializer=rag__engine__pb2.InitRequest.SerializeToString, + response_deserializer=rag__engine__pb2.InitResponse.FromString, + _registered_method=True) + self.EmbedScholarshipBatch = channel.unary_unary( + '/fi.rag.v1.VectorDBService/EmbedScholarshipBatch', + request_serializer=rag__engine__pb2.EmbedScholarshipBatchRequest.SerializeToString, + response_deserializer=rag__engine__pb2.EmbedScholarshipBatchResponse.FromString, + _registered_method=True) + + +class VectorDBServiceServicer(object): + """========================================= + VectorDBService - declare RPC methods + ========================================= + """ + + def Init(self, request, context): + """Initialize vector DB connection or collection + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def EmbedScholarshipBatch(self, request, context): + """Embed a batch of scholarships and store them + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_VectorDBServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Init': grpc.unary_unary_rpc_method_handler( + servicer.Init, + request_deserializer=rag__engine__pb2.InitRequest.FromString, + response_serializer=rag__engine__pb2.InitResponse.SerializeToString, + ), + 'EmbedScholarshipBatch': grpc.unary_unary_rpc_method_handler( + servicer.EmbedScholarshipBatch, + request_deserializer=rag__engine__pb2.EmbedScholarshipBatchRequest.FromString, + response_serializer=rag__engine__pb2.EmbedScholarshipBatchResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'fi.rag.v1.VectorDBService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('fi.rag.v1.VectorDBService', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class VectorDBService(object): + """========================================= + VectorDBService - declare RPC methods + ========================================= + """ + + @staticmethod + def Init(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/fi.rag.v1.VectorDBService/Init', + rag__engine__pb2.InitRequest.SerializeToString, + rag__engine__pb2.InitResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def EmbedScholarshipBatch(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/fi.rag.v1.VectorDBService/EmbedScholarshipBatch', + rag__engine__pb2.EmbedScholarshipBatchRequest.SerializeToString, + rag__engine__pb2.EmbedScholarshipBatchResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/backend/services/llm_manager/TODO.md b/backend/services/llm_manager/TODO.md new file mode 100644 index 0000000..0429365 --- /dev/null +++ b/backend/services/llm_manager/TODO.md @@ -0,0 +1,10 @@ +# TODO + +- [ ] **Additional Providers**: Azure OpenAI, AWS Bedrock, Google Vertex AI +- [ ] **Request Caching**: Cache repeated queries to reduce costs +- [ ] **Performance Metrics**: Track latency and throughput per model +- [ ] **Function Calling**: Support for tool use and function calling +- [ ] **Rate Limiting**: Per-user/session request limits +- [ ] **Cost Budgets**: Alerts when spending exceeds thresholds +- [ ] **Token Estimation**: Pre-calculate tokens before sending requests +- [ ] **Request Batching**: Batch multiple requests for efficiency \ No newline at end of file diff --git a/backend/services/rag_engine/README.md b/backend/services/rag_engine/README.md new file mode 100644 index 0000000..010acd8 --- /dev/null +++ b/backend/services/rag_engine/README.md @@ -0,0 +1,14 @@ +services + +1. vector store interface (context management) +2. embedding service (upload docs) +3. retrieval engine (fill in scholarship) +4. context builder (builds context using vector store) +5. llm client (communicates with llm manager, sends it stuff) +6. response processor (validates LLM responses) +7. query classifier (semantic / logical routing) + +8. main rag engine (server.py) +- config.py configures it + + diff --git a/backend/services/rag_engine/TODO.md b/backend/services/rag_engine/TODO.md new file mode 100644 index 0000000..b0d9c30 --- /dev/null +++ b/backend/services/rag_engine/TODO.md @@ -0,0 +1,26 @@ +1. Make cleanup scripts +2. make test scripts (as part of the test folder) +3. finish document upload logic for users (non referential) +4. finish document upload logic for organizations (non referential) +5. begin retrieval logic for matcher (this may be hard) + +VectorDBService +- init +- embed_scholarship_batch +- embed_pdf_lazy +- embed_text +- _batch_add_documents +- filter_duplicates + +- _cached_retrieval +- retrieve_scholarships_for_user +- retrieve_user_documents +- match_scholarships +- generate_form_filling_plan + +utility (part of VectorDBService) +- _hash_content +- _format_user_profile +- clear_cache + +database initialization \ No newline at end of file diff --git a/backend/services/rag_engine/archive/rag.py b/backend/services/rag_engine/archive/rag.py new file mode 100644 index 0000000..8ab3e0e --- /dev/null +++ b/backend/services/rag_engine/archive/rag.py @@ -0,0 +1,33 @@ + +class VectorStore: + def __init__(self, config: Dict[str, any] = None): + self.conn = psycopg2.connect( + dbname = config["dbname"], + user = config["user"], + password = config["password"], + host = config["host"], + port = config["port"] + ) + self.cur = self.conn.cursor() + print("connected to DB :)") + + #can be all-MiniLM-L12-v2 as well + def generate_embedding(text: str, model: str = "sentence-transformers/all-MiniLM-L6-v2") -> list: + embeddings = HuggingFaceEmbeddings(model_name = model) + vectors = embeddings.embed_documents(text) + return vectors + def insert_user_document(self, user: User): + sql_file_path = "../sql/insertUserDocument.sql" + sql_path = Path(sql_file_path) + with open(sql_path, 'r') as f: + query_template = f.read() + user_dict = asdict(user) + columns = ', '.join(user_dict.keys()) + placeholders = ', '.join([f'%s' for _ in user_dict]) + + query = query_template.replace("$1", columns).replace("$2", placeholders) + self.cur.execute(query, tuple(user_dict.values())) + print("document entered :)") + def close(self): + self.cur.close() + self.conn.close() \ No newline at end of file diff --git a/backend/services/rag_engine/archive/test.py b/backend/services/rag_engine/archive/test.py new file mode 100644 index 0000000..e984848 --- /dev/null +++ b/backend/services/rag_engine/archive/test.py @@ -0,0 +1,116 @@ +import pytest +import psycopg2 +import datetime +from unittest.mock import Mock, AsyncMock, patch, MagicMock +from typing import List, Dict, Any +from dataclasses import asdict +from pathlib import Path +from langchain_community.embeddings import HuggingFaceEmbeddings +from langchain_community.vectorstores.pgvector import PGVector +import os + +# Import the classes to test (assuming they're in rag_engine.py) +from core.rag import VectorStore, VectorDBService, User + +models_folder = "./../../../db/models" +db_folder = "./../../../db" + +@pytest.fixture(scope="session") +def test_db_config(): + """Test database configuration""" + return { + "dbname": "test_rag_db", # Separate test database + "user": "postgres", + "password": "", + "host": "localhost", + "port": 5432 + } + +def execute_sql_file(cursor, sql_file_path: str): + sql_path = Path(sql_file_path) + with open(sql_path, 'r') as f: + sql_script = f.read() + cursor.execute(sql_script) + +@pytest.fixture(scope="session") +def init_test_db(test_db_config): + conn = psycopg2.connect(**test_db_config) + conn.autocommit = True + cur = conn.cursor() + + execute_sql_file(cur, f"{models_folder}/references.sql") + execute_sql_file(cur, f"{models_folder}/opportunities.sql") + execute_sql_file(cur, f"{models_folder}/users.sql") + execute_sql_file(cur, f"{models_folder}/matches.sql") + execute_sql_file(cur, f"{models_folder}/indicies.sql") + yield cur + execute_sql_file(cur, f"{db_folder}/teardown.sql") + +@pytest.fixture(scope="function") +def vector_store(test_db_config, init_test_db): + """Create VectorStore instance and clean up after test""" + # Setup: Create instance + vs = VectorStore(config=test_db_config) + + #clean vector store db + + yield vs + + vs.close() + +class TestVectorStore: + def test_init_connection(self, test_db_config): + """Test database connection is established""" + vs = VectorStore(config=test_db_config) + + assert vs.conn is not None + assert vs.cur is not None + assert vs.conn.closed == 0 # 0 means open + + vs.close() + + def test_insert_user_document(self, vector_store): + user = User( + id=1, + username="isaacb", + email="isaac@example.com", + gpa=3.9, + major="CS", + grade="Senior", + graduation_date=datetime.datetime(2026, 5, 15), + university="Texas A&M University", + citizenship="USA", + location="College Station, TX", + min_award_amount=5000.0, + min_salary_amonut=60000.0 + ) + + vector_store.insert_user_document(user) + vector_store.conn.commit() + + # Verify it was inserted + vector_store.cur.execute(""" + SELECT user_id, document_type, document_text, document_embedding + FROM user_documents + WHERE user_id = 1 + """) + result = vector_store.cur.fetchone() + + assert result is not None + assert result[0] == 1 # user_id + assert result[1] == "resume" # document_type + assert result[2] == "Software Engineer with 5 years experience" + assert len(result[3]) == 384 # embedding + + +if __name__ == "__main__": + config = { + "dbname": "fiapply", + "user": "postgres", + "password": "", + "host": "localhost", + "port": "5432" + } + db = VectorStore(config) + db.close() + pytest.main([__file__, "-v"]) \ No newline at end of file diff --git a/backend/services/rag_engine/config.py b/backend/services/rag_engine/config.py index 53fc052..9d31f51 100644 --- a/backend/services/rag_engine/config.py +++ b/backend/services/rag_engine/config.py @@ -8,14 +8,20 @@ class RAGConfig: """RAG Engine configuration settings""" host: str = os.getenv("RAG_ENGINE_HOST", "0.0.0.0") port: int = int(os.getenv("RAG_ENGINE_PORT", "50053")) + connection_string: str = os.getenv( + "PG_CONN", + "postgresql+asyncpg://postgres:postgres@localhost:5432/vectordb" + ) # Database settings - db_path: str = os.getenv("DB_PATH", "db/fi.db") + # db_path: str = os.getenv("DB_PATH", "db/fi.db") # Embedding settings embedding_model: str = os.getenv("EMBEDDING_MODEL", "sentence-transformers/all-MiniLM-L6-v2") + batch_size: int = int(os.getenv("BATCH_SIZE", "100")) chunk_size: int = int(os.getenv("CHUNK_SIZE", "512")) chunk_overlap: int = int(os.getenv("CHUNK_OVERLAP", "50")) + cache_size: int = int(os.getenv("CACHE_SIZE", "128")) # Search settings default_search_limit: int = int(os.getenv("DEFAULT_SEARCH_LIMIT", "5")) diff --git a/backend/services/rag_engine/conftest.py b/backend/services/rag_engine/conftest.py new file mode 100644 index 0000000..2961c9f --- /dev/null +++ b/backend/services/rag_engine/conftest.py @@ -0,0 +1,5 @@ +import sys +from pathlib import Path + +# Add the project root to Python path +sys.path.insert(0, str(Path(__file__).parent)) \ No newline at end of file diff --git a/backend/services/rag_engine/test.py b/backend/services/rag_engine/core/__init__.py similarity index 100% rename from backend/services/rag_engine/test.py rename to backend/services/rag_engine/core/__init__.py diff --git a/backend/services/rag_engine/core/rag.py b/backend/services/rag_engine/core/rag.py new file mode 100644 index 0000000..fe6eba8 --- /dev/null +++ b/backend/services/rag_engine/core/rag.py @@ -0,0 +1,298 @@ +import grpc +import asyncio +import uuid +import signal +import datetime +from backend.shared.utils import logs +from typing import List, Dict, Any, Optional, Tuple +from dataclasses import dataclass, asdict +from enum import Enum +from pathlib import Path +import os +# import haslib +from functools import lru_cache +import psycopg2 +import asyncpg + +from langchain import hub + +from langchain_huggingface import HuggingFaceEmbeddings +from langchain.text_splitter import RecursiveCharacterTextSplitter +from langchain_postgres import PGEngine, PGVector +from langchain_postgres.vectorstores import DistanceStrategy +from langchain_community.llms import HuggingFacePipeline +from langchain.chains import RetrievalQA +from langchain.schema import Document +from langchain_core.runnables import RunnablePassthrough +from langchain_core.output_parsers import StrOutputParser +from langchain_community.document_loaders import PyPDFLoader +from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM, AutoModelForSeq2SeqLM +from langchain_openai import ChatOpenAI +from functools import lru_cache +from dotenv import load_dotenv + +# from grpc_health.v1 import health, health_pb2, health_pb2_grpc +# from grpc_reflection.v1alpha import reflection +# from google.protobuf import struct_pb2 + + +from backend.generated import rag_engine_pb2, rag_engine_pb2_grpc, common_pb2 +from backend.services.rag_engine.config import RAGConfig, config as default_config +from backend.services.llm_manager.utils.error_handler import ErrorHandler + +load_dotenv() + +sql_folder = "../sql" + +# datamodels +@dataclass +class User: + id: int + username: str + email: str + gpa: float + major: str #id + grade: str #id + graduation_date: datetime.datetime + university: str + citizenship: str #id + location: str #could replace w/ long lat + min_award_amount: float + min_salary_amonut: float + interests: List[str] # e.g., AI, Robotics, Community Service + extracurriculars: List[str] + essay_keywords: List[str] # optional for keyword matching + # career goals who the fuck cares about those + # essays who wants to read ur ugly ahh essays + # transcripts who wants to look at ur ugly ahh transcript + + def to_search_query(self) -> str: + """Generate optimized search query from user profile""" + return ( + f"GPA: {self.gpa}, Major: {self.major}, " + f"Interests: {', '.join(self.interests)}, " # fuck no i aint limtiing to no top 3 + f"Extracurriculars: {', '.join(self.extracurriculars)}" + f"Location: {self.location}, Citizenship: {self.citizenship}" + ) + +@dataclass +class Scholarship: + id: int + name: str + description: str + min_gpa: float + eligible_majors: List[str] + citizenship_required: Optional[str] + location: Optional[str] + award_amount: str + keywords: List[str] + + def to_document_content(self) -> str: + """Convert scholarship to searchable text""" + return ( + f"Scholarship: {self.name}\n" + f"Award: {self.award_amount}\n" + f"Minimum GPA: {self.min_gpa}\n" + f"Eligible Majors: {', '.join(self.eligible_majors)}\n" + f"Citizenship: {self.citizenship_required or 'Any'}\n" + f"Location: {self.location or 'Any'}\n" + f"Description: {self.description}\n" + f"Keywords: {', '.join(self.keywords)}" + ) + + +class DocumentType: + SCHOLARSHIP = "scholarship" + RESUME = "resume" + ESSAY = "essay" + TRANSCRIPT = "transcript" + FORM_CONTEXT = "form_context" + USER_PROFILE = "user_profile" + +conn = os.getenv('PG_CONN', "postgresql+psycopg2://postgres:postgres@localhost:5432/vectordb") + +class VectorDBService(rag_engine_pb2_grpc.VectorDBServiceServicer): + """ + Production-ready vector database service with: + - Lazy loading and batch processing - NO + - Connection pooling - YES + - Metadata enrichment - NO + - Token-aware chunking - NO + - Error handling - NO + - Caching - NO + """ + + def __init__(self, config: RAGConfig = None): + self.config = config or default_config + self.embeddings = HuggingFaceEmbeddings(model_name=self.config.embedding_model, + encode_kwargs = { + 'batch-size': self.config.batch_size, + 'normalize-embeddings': True + }) + self.splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder( + encoding_name="cl100k_base", + chunk_size=self.config.chunk_size, # characters per chunk + chunk_overlap=self.config.chunk_overlap, # overlap between chunks to preserve context + separators=["\n\n", "\n", ". ", " ", ""] + ) + self.llm = ChatOpenAI(model_name = "gpt-5-nano", temperature=0) + self.engine: Optional[PGEngine] = None + self.vs: Optional[PGVector] = None + # self.error_handler = ErrorHandler() + + async def Init(self, request:rag_engine_pb2.InitRequest, + context: grpc.aio.ServicerContext) -> rag_engine_pb2.InitResponse: + print("I'm gonna init.") + try: + connection_string = request.connection_string + collection_name = request.collection_name + self.engine = await asyncio.to_thread( + PGEngine.from_connection_string, + url = connection_string, + pool_size=5, + max_overflow=10 + ) + self.vs = await asyncio.to_thread( + PGVector, + connection=connection_string, + collection_name=collection_name, + embeddings=self.embeddings, + distance_strategy=DistanceStrategy.COSINE, + async_mode=True + ) + self.retriever = self.vs.as_retriever() + logs.info("VectorDB Service Initialized Successfully") + return rag_engine_pb2.InitResponse(success = True) + except Exception as e: + logs.error(f"Error During Init: {e}") + return rag_engine_pb2.InitResponse(error = e) + + async def __getattr__(self, name): + print("gRPC called:", name) + raise AttributeError(f"No method {name}") + + #document embedding services + async def EmbedScholarshipBatch(self, request: rag_engine_pb2.EmbedScholarshipBatchRequest, + context: grpc.aio.ServicerContext) -> rag_engine_pb2.EmbedScholarshipBatchResponse: + print("Handler called!!") + trace_id=str(uuid.uuid4()) + scholarships = request.scholarships + try: + documents = [] + for s in scholarships: + eligible_majors = list(s.eligible_majors) if hasattr(s, "eligible_majors") else [] + keywords = list(s.keywords) if hasattr(s, "keywords") else [] + content = ( + f"Scholarship: {getattr(s, 'name', '')}\n" + f"Award: {getattr(s, 'award_amount', '')}\n" + f"Minimum GPA: {getattr(s, 'min_gpa', '')}\n" + f"Eligible Majors: {', '.join(eligible_majors)}\n" + f"Citizenship: {getattr(s, 'citizenship_required', '') or 'Any'}\n" + f"Location: {getattr(s, 'location', '') or 'Any'}\n" + f"Description: {getattr(s, 'description', '')}\n" + f"Keywords: {', '.join(keywords)}" + ) + + # safe content hash (use existing method if present) + if hasattr(self, "_hash_content") and callable(getattr(self, "_hash_content")): + content_hash = self._hash_content(content) + else: + # fallback simple stable hash + content_hash = uuid.uuid5(uuid.NAMESPACE_DNS, content).hex + + doc = Document( + page_content=content, + metadata={ + "doc_type": DocumentType.SCHOLARSHIP, + "scholarship_id": getattr(s, "id", None), + "scholarship_name": getattr(s, "name", ""), + "min_gpa": getattr(s, "min_gpa", None), + "award_amount": getattr(s, "award_amount", ""), + "location": getattr(s, "location", "any"), + "citizenship": getattr(s, "citizenship_required", "any"), + "majors": ",".join(eligible_majors), + "created_at": datetime.datetime.now().isoformat(), + "content_hash": content_hash + } + ) + documents.append(doc) + chunks = self.splitter.split_documents(documents) + total_added = await self._batch_add_documents(chunks) + logs.info(f"Embedded {len(scholarships)} scholarships as {total_added} chunks") + return rag_engine_pb2.EmbedScholarshipBatchResponse(count=total_added) + except Exception as e: + logs.error(f"Error embedding scholarships: {e}") + try: + context.set_details(str(e)) + context.set_code(grpc.StatusCode.INTERNAL) + except Exception: + pass + # error = self.error_handler.from_exception(e, trace_id, include_stack=True) + return rag_engine_pb2.EmbedScholarshipBatchResponse(error=e) + + async def EmbedPDFLazy( + self, + pdf_path: str, + doc_type: str, + user_id: int, + additional_metadata: Optional[Dict[str, Any]] = None + ) -> int: + """ + Embed PDF using lazy loading and batch processing + + Args: + pdf_path: Path to PDF file + doc_type: Type of document (resume, essay, etc.) + user_id: User ID for filtering + additional_metadata: Optional metadata to attach + + Returns: + Number of chunks created + """ + try: + if not Path(pdf_path).exists(): + raise FileNotFoundError(f"PDF not found: {pdf_path}") + loader = PyPDFLoader(pdf_path) + documents = [] + for page_num, doc in enumerate(loader.lazy_load(), start = 1): + # Enrich metadata + doc.metadata.update({ + "doc_type": doc_type, + "user_id": user_id, + "source_file": Path(pdf_path).name, + "page_number": page_num, + "created_at": datetime.now().isoformat(), + "content_hash": self._hash_content(doc.page_content) + }) + except Exception as e: + logs.error(f"Error embedding scholarships: {e}") + raise + + async def _batch_add_documents(self, chunks: List[Document]) -> int: + total_added = 0 + for i in range(0, len(chunks), self.BATCH_SIZE): + batch = chunks[i:i + self.BATCH_SIZE] + try: + unique_batch = await self._filter_duplicates(batch) + if unique_batch: + self.vs.add_documents(unique_batch) + total_added += len(unique_batch) + + if total_added % 500 == 0: + logs.info(f"Progress: {total_added}/{len(chunks)} chunks processed") + + except Exception as e: + logs.error(f"Error adding batch {i//self.BATCH_SIZE}: {e}") + # Continue with next batch instead of failing completely + return total_added + + async def _filter_duplicates(self, documents: List[Document]) -> List[Document]: + #TODO: add filtering + return documents + + #utility methods + + +#initialize database + +#main method \ No newline at end of file diff --git a/backend/services/rag_engine/example.py b/backend/services/rag_engine/example.py new file mode 100644 index 0000000..8d8451c --- /dev/null +++ b/backend/services/rag_engine/example.py @@ -0,0 +1,728 @@ +import asyncio +import logging #!! Replace this logger with shared logger +from typing import List, Dict, Any, Optional +from dataclasses import dataclass, asdict +from datetime import datetime +from pathlib import Path +import hashlib +from functools import lru_cache + +from langchain import hub +from langchain_huggingface import HuggingFaceEmbeddings +from langchain_text_splitters import RecursiveCharacterTextSplitter +from langchain_postgres import PGVector, PGEngine +from langchain_postgres.vectorstores import DistanceStrategy +from langchain_openai import ChatOpenAI +from langchain.schema import Document +from langchain_core.runnables import RunnablePassthrough +from langchain_core.output_parsers import StrOutputParser +from langchain_community.document_loaders import PyPDFLoader +from dotenv import load_dotenv +import os + +load_dotenv() +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# ============================================================================ +# DATA MODELS +# ============================================================================ + +@dataclass +class User: + id: int + username: str + email: str + gpa: float + major: str + grade: str + graduation_date: datetime + university: str + citizenship: str + location: str + min_award_amount: float + min_salary_amount: float + interests: List[str] + extracurriculars: List[str] + essay_keywords: List[str] + + def to_search_query(self) -> str: + """Generate optimized search query from user profile""" + return ( + f"GPA: {self.gpa}, Major: {self.major}, " + f"Interests: {', '.join(self.interests[:3])}, " # Limit to top 3 + f"Location: {self.location}, Citizenship: {self.citizenship}" + ) + +@dataclass +class Scholarship: + id: int + name: str + description: str + min_gpa: float + eligible_majors: List[str] + citizenship_required: Optional[str] + location: Optional[str] + award_amount: str + keywords: List[str] + + def to_document_content(self) -> str: + """Convert scholarship to searchable text""" + return ( + f"Scholarship: {self.name}\n" + f"Award: {self.award_amount}\n" + f"Minimum GPA: {self.min_gpa}\n" + f"Eligible Majors: {', '.join(self.eligible_majors)}\n" + f"Citizenship: {self.citizenship_required or 'Any'}\n" + f"Location: {self.location or 'Any'}\n" + f"Description: {self.description}\n" + f"Keywords: {', '.join(self.keywords)}" + ) + +# ============================================================================ +# DOCUMENT TYPES ENUM +# ============================================================================ + +class DocumentType: + SCHOLARSHIP = "scholarship" + RESUME = "resume" + ESSAY = "essay" + TRANSCRIPT = "transcript" + FORM_CONTEXT = "form_context" + USER_PROFILE = "user_profile" + +# ============================================================================ +# VECTOR DATABASE SERVICE +# ============================================================================ + +class VectorDBService: + """ + Production-ready vector database service with: + - Lazy loading and batch processing + - Connection pooling + - Metadata enrichment + - Token-aware chunking + - Error handling + - Caching + """ + + BATCH_SIZE = 100 + CHUNK_SIZE = 500 # tokens + CHUNK_OVERLAP = 50 + CACHE_SIZE = 128 + + def __init__(self, connection_string: str): + self.connection_string = connection_string + + # Initialize embeddings with optimal settings for consumer hardware + self.embeddings = HuggingFaceEmbeddings( + model_name="sentence-transformers/all-MiniLM-L6-v2", + model_kwargs={'device': 'cpu'}, # or 'mps'/'cuda' based on hardware + encode_kwargs={ + 'batch_size': 32, # Reduced for consumer hardware + 'normalize_embeddings': True + } + ) + + # Initialize connection pool + self.engine = PGEngine.from_connection_string( + url=connection_string, + pool_size=5, + max_overflow=10 + ) + + # Initialize vector store + self.vs = PGVector( + connection=connection_string, + collection_name="user_docs", + embeddings=self.embeddings, + distance_strategy=DistanceStrategy.COSINE, + use_jsonb=True # Better metadata query performance + ) + + # Token-aware text splitter + self.splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder( + encoding_name="cl100k_base", + chunk_size=self.CHUNK_SIZE, + chunk_overlap=self.CHUNK_OVERLAP, + separators=["\n\n", "\n", ". ", " ", ""] + ) + + # Initialize LLM (fix model name) + self.llm = ChatOpenAI( + model_name="gpt-4o-mini", # Fixed: was "gpt-5-nano" + temperature=0 + ) + + logger.info("VectorDBService initialized successfully") + + # ======================================================================== + # DOCUMENT EMBEDDING METHODS + # ======================================================================== + + async def embed_scholarship_batch( + self, + scholarships: List[Scholarship] + ) -> int: + """ + Embed multiple scholarships efficiently with batch processing + + Returns: + Number of chunks created + """ + try: + documents = [] + + for scholarship in scholarships: + content = scholarship.to_document_content() + + # Create document with rich metadata for filtering + doc = Document( + page_content=content, + metadata={ + "doc_type": DocumentType.SCHOLARSHIP, + "scholarship_id": scholarship.id, + "scholarship_name": scholarship.name, + "min_gpa": scholarship.min_gpa, + "award_amount": scholarship.award_amount, + "location": scholarship.location or "any", + "citizenship": scholarship.citizenship_required or "any", + "majors": ",".join(scholarship.eligible_majors), + "created_at": datetime.now().isoformat(), + "content_hash": self._hash_content(content) + } + ) + documents.append(doc) + + # Split documents into chunks + chunks = self.splitter.split_documents(documents) + + # Batch insert + total_added = await self._batch_add_documents(chunks) + + logger.info(f"Embedded {len(scholarships)} scholarships as {total_added} chunks") + return total_added + + except Exception as e: + logger.error(f"Error embedding scholarships: {e}") + raise + + async def embed_pdf_lazy( + self, + pdf_path: str, + doc_type: str, + user_id: int, + additional_metadata: Optional[Dict[str, Any]] = None + ) -> int: + """ + Embed PDF using lazy loading and batch processing + + Args: + pdf_path: Path to PDF file + doc_type: Type of document (resume, essay, etc.) + user_id: User ID for filtering + additional_metadata: Optional metadata to attach + + Returns: + Number of chunks created + """ + try: + if not Path(pdf_path).exists(): + raise FileNotFoundError(f"PDF not found: {pdf_path}") + + loader = PyPDFLoader(pdf_path) + documents = [] + + # Lazy load pages one at a time + for page_num, doc in enumerate(loader.lazy_load(), start=1): + # Enrich metadata + doc.metadata.update({ + "doc_type": doc_type, + "user_id": user_id, + "source_file": Path(pdf_path).name, + "page_number": page_num, + "created_at": datetime.now().isoformat(), + "content_hash": self._hash_content(doc.page_content) + }) + + if additional_metadata: + doc.metadata.update(additional_metadata) + + documents.append(doc) + + # Process in batches to avoid memory issues + if len(documents) >= 50: # Process every 50 pages + chunks = self.splitter.split_documents(documents) + await self._batch_add_documents(chunks) + documents = [] # Clear batch + + # Process remaining documents + if documents: + chunks = self.splitter.split_documents(documents) + total_added = await self._batch_add_documents(chunks) + else: + total_added = 0 + + logger.info(f"Embedded PDF '{pdf_path}' as {total_added} chunks") + return total_added + + except Exception as e: + logger.error(f"Error embedding PDF {pdf_path}: {e}") + raise + + async def embed_text( + self, + text: str, + doc_type: str, + user_id: int, + metadata: Optional[Dict[str, Any]] = None + ) -> int: + """ + Embed text content with metadata + + Args: + text: Text content to embed + doc_type: Type of document + user_id: User ID for filtering + metadata: Optional additional metadata + + Returns: + Number of chunks created + """ + try: + doc = Document( + page_content=text, + metadata={ + "doc_type": doc_type, + "user_id": user_id, + "created_at": datetime.now().isoformat(), + "content_hash": self._hash_content(text), + **(metadata or {}) + } + ) + + chunks = self.splitter.split_documents([doc]) + total_added = await self._batch_add_documents(chunks) + + logger.info(f"Embedded text as {total_added} chunks") + return total_added + + except Exception as e: + logger.error(f"Error embedding text: {e}") + raise + + async def _batch_add_documents(self, chunks: List[Document]) -> int: + """ + Add documents in batches for optimal performance + + Args: + chunks: Document chunks to add + + Returns: + Total number of chunks added + """ + total_added = 0 + + for i in range(0, len(chunks), self.BATCH_SIZE): + batch = chunks[i:i + self.BATCH_SIZE] + + try: + # Check for duplicates using content hash + unique_batch = await self._filter_duplicates(batch) + + if unique_batch: + self.vs.add_documents(unique_batch) + total_added += len(unique_batch) + + if total_added % 500 == 0: + logger.info(f"Progress: {total_added}/{len(chunks)} chunks processed") + + except Exception as e: + logger.error(f"Error adding batch {i//self.BATCH_SIZE}: {e}") + # Continue with next batch instead of failing completely + + return total_added + + async def _filter_duplicates(self, documents: List[Document]) -> List[Document]: + """ + Filter out duplicate documents based on content hash + + This is a simple implementation. For production, consider: + - Using a separate deduplication table + - Implementing more sophisticated similarity detection + """ + # For now, return all (implement deduplication logic as needed) + return documents + + # ======================================================================== + # RETRIEVAL METHODS + # ======================================================================== + + @lru_cache(maxsize=CACHE_SIZE) + def _cached_retrieval( + self, + query: str, + doc_type: Optional[str], + user_id: Optional[int], + k: int + ) -> tuple: + """ + Cached retrieval to avoid repeated DB queries + Returns tuple for hashability (required by lru_cache) + """ + filter_dict = {} + + if doc_type: + filter_dict["doc_type"] = doc_type + if user_id: + filter_dict["user_id"] = user_id + + docs = self.vs.similarity_search( + query=query, + k=k, + filter=filter_dict if filter_dict else None + ) + + # Convert to tuple of tuples for caching + return tuple((doc.page_content, tuple(doc.metadata.items())) for doc in docs) + + async def retrieve_scholarships_for_user( + self, + user: User, + k: int = 10 + ) -> List[Document]: + """ + Retrieve relevant scholarships with filtering + + Args: + user: User profile + k: Number of results + + Returns: + List of relevant scholarship documents + """ + try: + query = user.to_search_query() + + # Use cached retrieval + cached_results = self._cached_retrieval( + query=query, + doc_type=DocumentType.SCHOLARSHIP, + user_id=None, # Scholarships aren't user-specific + k=k + ) + + # Convert back to Document objects + docs = [ + Document(page_content=content, metadata=dict(metadata)) + for content, metadata in cached_results + ] + + logger.info(f"Retrieved {len(docs)} scholarships for user {user.id}") + return docs + + except Exception as e: + logger.error(f"Error retrieving scholarships: {e}") + raise + + async def retrieve_user_documents( + self, + user_id: int, + doc_type: Optional[str] = None, + k: int = 5 + ) -> List[Document]: + """ + Retrieve user's documents (resume, essays, etc.) + + Args: + user_id: User ID + doc_type: Optional document type filter + k: Number of results + + Returns: + List of user documents + """ + try: + query = f"user_id:{user_id}" + + cached_results = self._cached_retrieval( + query=query, + doc_type=doc_type, + user_id=user_id, + k=k + ) + + docs = [ + Document(page_content=content, metadata=dict(metadata)) + for content, metadata in cached_results + ] + + return docs + + except Exception as e: + logger.error(f"Error retrieving user documents: {e}") + raise + + # ======================================================================== + # LLM-POWERED METHODS + # ======================================================================== + + async def match_scholarships( + self, + user: User, + top_k: int = 10 + ) -> Dict[str, Any]: + """ + Match user to scholarships using LLM + + Args: + user: User profile + top_k: Number of scholarships to consider + + Returns: + Dictionary with matches and reasoning + """ + try: + docs = await self.retrieve_scholarships_for_user(user, k=top_k) + + if not docs: + return { + "matches": [], + "message": "No scholarships found matching criteria" + } + + context = "\n\n---\n\n".join(doc.page_content for doc in docs) + + prompt = f"""You are a scholarship matching assistant. Analyze the user profile and scholarships to provide matches. + +USER PROFILE: +{self._format_user_profile(user)} + +AVAILABLE SCHOLARSHIPS: +{context} + +TASK: +Return a JSON array of matched scholarships with: +1. scholarship_name +2. match_score (0-100) +3. match_reasons (list of strings explaining why this is a good match) +4. potential_concerns (list of strings about requirements that might be challenging) + +Format your response as valid JSON only.""" + + response = await self.llm.ainvoke(prompt) + + return { + "matches": response.content, + "total_considered": len(docs) + } + + except Exception as e: + logger.error(f"Error matching scholarships: {e}") + raise + + async def generate_form_filling_plan( + self, + html_content: str, + user_id: int + ) -> str: + """ + Generate form filling plan using RAG + + Args: + html_content: HTML form content + user_id: User ID for context retrieval + + Returns: + JSON string with filling instructions + """ + try: + # Retrieve user context + user_docs = await self.retrieve_user_documents( + user_id=user_id, + doc_type=None, # Get all user documents + k=5 + ) + + # Also retrieve form examples if available + form_examples = self.vs.similarity_search( + query=html_content[:500], # Use HTML snippet as query + k=3, + filter={"doc_type": DocumentType.FORM_CONTEXT} + ) + + def format_docs(docs: List[Document]) -> str: + return "\n\n".join(doc.page_content for doc in docs) + + prompt = hub.pull("rlm/rag-prompt") + + rag_chain = ( + { + "context": RunnablePassthrough(), + "question": RunnablePassthrough() + } + | prompt + | self.llm + | StrOutputParser() + ) + + context = f"""USER CONTEXT: +{format_docs(user_docs)} + +PREVIOUS FORM EXAMPLES: +{format_docs(form_examples)}""" + + query = f"""You are a web automation assistant. + +Given the HTML form below and the user's context, generate a JSON response with: +1. fields_to_fill: Array of objects with: + - field_name: Name of the form field + - selector: CSS selector to find the field + - value: Value to fill (from user context) + - field_type: Type of field (text, select, checkbox, etc.) +2. validation_checks: Array of checks to perform before submission +3. actions: Ordered list of steps to fill the form + +HTML FORM: +{html_content[:2000]} # Limit HTML size + +Return valid JSON only.""" + + response = await rag_chain.ainvoke({ + "context": context, + "question": query + }) + + return response + + except Exception as e: + logger.error(f"Error generating form filling plan: {e}") + raise + + # ======================================================================== + # UTILITY METHODS + # ======================================================================== + + @staticmethod + def _hash_content(content: str) -> str: + """Generate hash of content for deduplication""" + return hashlib.sha256(content.encode()).hexdigest()[:16] + + @staticmethod + def _format_user_profile(user: User) -> str: + """Format user profile for LLM consumption""" + return f""" +- GPA: {user.gpa} +- Major: {user.major} +- Grade Level: {user.grade} +- Graduation: {user.graduation_date.strftime('%Y-%m')} +- University: {user.university} +- Citizenship: {user.citizenship} +- Location: {user.location} +- Min Award: ${user.min_award_amount} +- Interests: {', '.join(user.interests)} +- Extracurriculars: {', '.join(user.extracurriculars)} +""" + + def clear_cache(self): + """Clear the retrieval cache""" + self._cached_retrieval.cache_clear() + logger.info("Cache cleared") + +# ============================================================================ +# DATABASE INITIALIZATION +# ============================================================================ + +async def initialize_database(connection_string: str): + """ + Initialize database with proper indexes for pgvector + + Run this once after creating your vector store + """ + import psycopg2 + + try: + conn = psycopg2.connect(connection_string.replace("postgresql+psycopg2://", "postgresql://")) + cur = conn.cursor() + + logger.info("Creating pgvector indexes...") + + # Create IVFFlat index (recommended for consumer hardware) + # Adjust 'lists' based on your data size: sqrt(row_count) is a good start + cur.execute(""" + CREATE INDEX IF NOT EXISTS user_docs_ivfflat_idx + ON langchain_pg_embedding + USING ivfflat (embedding vector_cosine_ops) + WITH (lists = 100); + """) + + # Create indexes on metadata for faster filtering + cur.execute(""" + CREATE INDEX IF NOT EXISTS user_docs_doctype_idx + ON langchain_pg_embedding ((cmetadata->>'doc_type')); + """) + + cur.execute(""" + CREATE INDEX IF NOT EXISTS user_docs_userid_idx + ON langchain_pg_embedding ((cmetadata->>'user_id')); + """) + + conn.commit() + cur.close() + conn.close() + + logger.info("Database indexes created successfully") + + except Exception as e: + logger.error(f"Error initializing database: {e}") + raise + +# ============================================================================ +# USAGE EXAMPLE +# ============================================================================ + +async def main(): + """Example usage""" + connection_string = os.getenv( + 'PG_CONN', + "postgresql+psycopg://postgres:postgres@localhost:5432/vectordb" + ) + + service = VectorDBService(connection_string) + + # Initialize database indexes (run once) + # await initialize_database(connection_string) + + # Example: Embed a PDF resume + chunks = await service.embed_pdf_lazy( + pdf_path="path/to/resume.pdf", + doc_type=DocumentType.RESUME, + user_id=123, + additional_metadata={"resume_version": "2024"} + ) + print(f"Embedded resume as {chunks} chunks") + + # Example: Match scholarships + user = User( + id=123, + username="john_doe", + email="john@example.com", + gpa=3.8, + major="Computer Science", + grade="Junior", + graduation_date=datetime(2026, 5, 15), + university="State University", + citizenship="US", + location="California", + min_award_amount=1000.0, + min_salary_amount=60000.0, + interests=["AI", "Robotics", "Community Service"], + extracurriculars=["IEEE", "Volunteer Teaching"], + essay_keywords=["innovation", "technology", "impact"] + ) + + matches = await service.match_scholarships(user, top_k=5) + print(f"Found {matches['total_considered']} potential matches") + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/backend/services/rag_engine/rag_dummy.py b/backend/services/rag_engine/rag_dummy.py new file mode 100644 index 0000000..8f3987f --- /dev/null +++ b/backend/services/rag_engine/rag_dummy.py @@ -0,0 +1,724 @@ +import grpc +from typing import List, Dict, Any, Optional, Tuple +from dataclasses import dataclass +from enum import Enum + + +# ============================================================================ +# DATA MODELS +# ============================================================================ + +@dataclass +class Document: + """Represents a document in the RAG system""" + id: str + content: str + metadata: Dict[str, Any] + embedding: Optional[List[float]] = None + + +@dataclass +class Scholarship: + """Represents a scholarship opportunity""" + id: str + name: str + organization: str + deadline: str + requirements: List[str] + essay_prompts: List[str] + eligibility_criteria: Dict[str, Any] + award_amount: str + metadata: Dict[str, Any] + + +@dataclass +class UserProfile: + """Represents a user's application profile""" + user_id: str + resume: str + transcripts: List[str] + past_essays: List[Document] + achievements: List[str] + personal_info: Dict[str, Any] + metadata: Dict[str, Any] + + +@dataclass +class RetrievalResult: + """Result from a vector search query""" + document: Document + score: float + rank: int + + +@dataclass +class RAGContext: + """Compiled context for LLM prompt""" + retrieved_documents: List[RetrievalResult] + user_profile: Optional[UserProfile] + scholarship_info: Optional[Scholarship] + conversation_history: List[Dict[str, str]] + metadata: Dict[str, Any] + + +class QueryType(Enum): + """Types of queries the RAG engine handles""" + SCHOLARSHIP_SEARCH = "scholarship_search" + ESSAY_GENERATION = "essay_generation" + ELIGIBILITY_CHECK = "eligibility_check" + GENERAL_QUESTION = "general_question" + DOCUMENT_SUMMARY = "document_summary" + + +# ============================================================================ +# VECTOR STORE INTERFACE +# ============================================================================ + +class VectorStore: + """Handles vector database operations""" + + def __init__(self, config: Dict[str, Any]): + """Initialize vector store with configuration + + Args: + config: Database configuration (connection string, credentials, etc.) + """ + pass + + async def add_documents(self, documents: List[Document]) -> List[str]: + """Add documents to the vector store + + Args: + documents: List of documents to add + + Returns: + List of document IDs that were added + """ + pass + + async def update_document(self, document_id: str, document: Document) -> bool: + """Update an existing document + + Args: + document_id: ID of document to update + document: Updated document + + Returns: + True if successful, False otherwise + """ + pass + + async def delete_document(self, document_id: str) -> bool: + """Delete a document from the vector store + + Args: + document_id: ID of document to delete + + Returns: + True if successful, False otherwise + """ + pass + + async def search(self, + query_embedding: List[float], + top_k: int = 5, + filters: Optional[Dict[str, Any]] = None) -> List[RetrievalResult]: + """Search for similar documents using vector similarity + + Args: + query_embedding: Query vector + top_k: Number of results to return + filters: Metadata filters to apply + + Returns: + List of retrieval results ranked by similarity + """ + pass + + async def get_document(self, document_id: str) -> Optional[Document]: + """Retrieve a specific document by ID + + Args: + document_id: ID of document to retrieve + + Returns: + Document if found, None otherwise + """ + pass + + +# ============================================================================ +# EMBEDDING SERVICE +# ============================================================================ + +class EmbeddingService: + """Handles text embedding generation""" + + def __init__(self, config: Dict[str, Any]): + """Initialize embedding service + + Args: + config: Service configuration (model name, API keys, etc.) + """ + pass + + async def embed_text(self, text: str) -> List[float]: + """Generate embedding for a single text + + Args: + text: Input text to embed + + Returns: + Embedding vector + """ + pass + + async def embed_batch(self, texts: List[str]) -> List[List[float]]: + """Generate embeddings for multiple texts + + Args: + texts: List of texts to embed + + Returns: + List of embedding vectors + """ + pass + + def get_embedding_dimension(self) -> int: + """Get the dimension of embeddings produced + + Returns: + Embedding dimension (e.g., 1536 for OpenAI ada-002) + """ + pass + + +# ============================================================================ +# RETRIEVAL ENGINE +# ============================================================================ + +class RetrievalEngine: + """Handles document retrieval logic""" + + def __init__(self, + vector_store: VectorStore, + embedding_service: EmbeddingService, + config: Dict[str, Any]): + """Initialize retrieval engine + + Args: + vector_store: Vector database instance + embedding_service: Embedding service instance + config: Retrieval configuration (top_k, thresholds, etc.) + """ + pass + + async def retrieve(self, + query: str, + query_type: QueryType, + filters: Optional[Dict[str, Any]] = None, + top_k: int = 5) -> List[RetrievalResult]: + """Retrieve relevant documents for a query + + Args: + query: User query text + query_type: Type of query being performed + filters: Metadata filters to apply + top_k: Number of results to return + + Returns: + List of relevant documents ranked by score + """ + pass + + async def retrieve_scholarships(self, + user_profile: UserProfile, + filters: Optional[Dict[str, Any]] = None) -> List[Scholarship]: + """Retrieve scholarships matching user profile + + Args: + user_profile: User's application profile + filters: Additional filters (deadline, amount, etc.) + + Returns: + List of matching scholarships + """ + pass + + async def retrieve_similar_essays(self, + essay_prompt: str, + user_id: str, + top_k: int = 3) -> List[Document]: + """Retrieve user's past essays similar to a prompt + + Args: + essay_prompt: Current essay prompt + user_id: User ID to filter by + top_k: Number of essays to return + + Returns: + List of similar past essays + """ + pass + + async def hybrid_search(self, + query: str, + filters: Optional[Dict[str, Any]] = None, + top_k: int = 5, + alpha: float = 0.5) -> List[RetrievalResult]: + """Perform hybrid search (vector + keyword) + + Args: + query: Search query + filters: Metadata filters + top_k: Number of results + alpha: Weight between vector (1.0) and keyword (0.0) search + + Returns: + Combined search results + """ + pass + + +# ============================================================================ +# CONTEXT BUILDER +# ============================================================================ + +class ContextBuilder: + """Builds context for LLM prompts""" + + def __init__(self, config: Dict[str, Any]): + """Initialize context builder + + Args: + config: Configuration (token limits, formatting options, etc.) + """ + pass + + async def build_context(self, + query: str, + query_type: QueryType, + retrieved_documents: List[RetrievalResult], + user_profile: Optional[UserProfile] = None, + scholarship: Optional[Scholarship] = None, + conversation_history: Optional[List[Dict[str, str]]] = None) -> RAGContext: + """Build complete context for LLM + + Args: + query: User query + query_type: Type of query + retrieved_documents: Documents from retrieval + user_profile: User's profile (if relevant) + scholarship: Scholarship details (if relevant) + conversation_history: Previous messages + + Returns: + Compiled RAG context + """ + pass + + def format_prompt(self, + context: RAGContext, + query: str, + system_prompt: Optional[str] = None) -> str: + """Format context into LLM prompt + + Args: + context: RAG context + query: User query + system_prompt: Optional system prompt override + + Returns: + Formatted prompt string + """ + pass + + def estimate_tokens(self, text: str) -> int: + """Estimate token count for text + + Args: + text: Input text + + Returns: + Estimated token count + """ + pass + + def truncate_to_token_limit(self, + text: str, + max_tokens: int) -> str: + """Truncate text to fit within token limit + + Args: + text: Input text + max_tokens: Maximum tokens allowed + + Returns: + Truncated text + """ + pass + + +# ============================================================================ +# LLM CLIENT +# ============================================================================ + +class LLMClient: + """Client for communicating with LLM Manager service""" + + def __init__(self, llm_manager_address: str): + """Initialize LLM client + + Args: + llm_manager_address: gRPC address of LLM Manager (e.g., 'localhost:50054') + """ + pass + + async def generate_completion(self, + prompt: str, + system_prompt: Optional[str] = None, + model: Optional[str] = None, + provider: Optional[str] = None, + temperature: float = 0.7, + max_tokens: int = 1000) -> Dict[str, Any]: + """Generate completion from LLM Manager + + Args: + prompt: User prompt + system_prompt: System prompt + model: Model to use + provider: Provider to use + temperature: Sampling temperature + max_tokens: Maximum tokens to generate + + Returns: + Completion response with content, usage, metadata + """ + pass + + async def stream_completion(self, + prompt: str, + system_prompt: Optional[str] = None, + model: Optional[str] = None, + provider: Optional[str] = None, + temperature: float = 0.7, + max_tokens: int = 1000): + """Stream completion from LLM Manager + + Args: + prompt: User prompt + system_prompt: System prompt + model: Model to use + provider: Provider to use + temperature: Sampling temperature + max_tokens: Maximum tokens to generate + + Yields: + Completion chunks + """ + pass + + +# ============================================================================ +# RESPONSE PROCESSOR +# ============================================================================ + +class ResponseProcessor: + """Processes and validates LLM responses""" + + def __init__(self, config: Dict[str, Any]): + """Initialize response processor + + Args: + config: Processing configuration + """ + pass + + async def process_essay_response(self, + response: str, + scholarship: Scholarship) -> Dict[str, Any]: + """Process and validate essay generation response + + Args: + response: LLM-generated essay + scholarship: Scholarship it's for + + Returns: + Processed essay with validation results + """ + pass + + async def validate_word_count(self, + text: str, + min_words: int, + max_words: int) -> Tuple[bool, int]: + """Validate text meets word count requirements + + Args: + text: Text to validate + min_words: Minimum word count + max_words: Maximum word count + + Returns: + (is_valid, actual_word_count) + """ + pass + + async def extract_structured_data(self, + response: str, + schema: Dict[str, Any]) -> Dict[str, Any]: + """Extract structured data from LLM response + + Args: + response: LLM response text + schema: Expected data schema + + Returns: + Extracted structured data + """ + pass + + async def fact_check(self, + claim: str, + source_documents: List[Document]) -> Dict[str, Any]: + """Fact-check a claim against source documents + + Args: + claim: Claim to verify + source_documents: Source documents to check against + + Returns: + Fact-check results with confidence and evidence + """ + pass + + +# ============================================================================ +# QUERY CLASSIFIER +# ============================================================================ + +class QueryClassifier: + """Classifies user queries into types""" + + def __init__(self, config: Dict[str, Any]): + """Initialize query classifier + + Args: + config: Classifier configuration + """ + pass + + async def classify(self, query: str) -> QueryType: + """Classify a user query + + Args: + query: User query text + + Returns: + Classified query type + """ + pass + + async def extract_intent(self, query: str) -> Dict[str, Any]: + """Extract detailed intent from query + + Args: + query: User query text + + Returns: + Intent details (entities, actions, filters, etc.) + """ + pass + + +# ============================================================================ +# MAIN RAG ENGINE +# ============================================================================ + +class RAGEngine: + """Main RAG Engine orchestrating all components""" + + def __init__(self, config: Dict[str, Any]): + """Initialize RAG Engine + + Args: + config: Complete RAG configuration + """ + pass + + async def initialize(self): + """Initialize all components and connections""" + pass + + async def query(self, + query: str, + user_id: str, + conversation_history: Optional[List[Dict[str, str]]] = None, + metadata: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: + """Main query interface for RAG engine + + Args: + query: User query + user_id: User making the query + conversation_history: Previous conversation messages + metadata: Additional context metadata + + Returns: + Response with answer, sources, and metadata + """ + pass + + async def generate_essay(self, + scholarship_id: str, + user_id: str, + essay_prompt: str, + additional_context: Optional[str] = None) -> Dict[str, Any]: + """Generate scholarship essay + + Args: + scholarship_id: ID of scholarship + user_id: User ID + essay_prompt: Essay prompt/question + additional_context: Any additional user-provided context + + Returns: + Generated essay with metadata and validation + """ + pass + + async def check_eligibility(self, + scholarship_id: str, + user_id: str) -> Dict[str, Any]: + """Check if user is eligible for a scholarship + + Args: + scholarship_id: ID of scholarship + user_id: User ID + + Returns: + Eligibility results with explanation + """ + pass + + async def search_scholarships(self, + user_id: str, + query: Optional[str] = None, + filters: Optional[Dict[str, Any]] = None, + top_k: int = 10) -> List[Scholarship]: + """Search for scholarships matching user profile + + Args: + user_id: User ID + query: Optional search query + filters: Optional filters (deadline, amount, etc.) + top_k: Number of results to return + + Returns: + List of matching scholarships + """ + pass + + async def add_scholarship(self, scholarship: Scholarship) -> str: + """Add a new scholarship to the system + + Args: + scholarship: Scholarship to add + + Returns: + Scholarship ID + """ + pass + + async def update_user_profile(self, user_profile: UserProfile) -> bool: + """Update user's profile in the system + + Args: + user_profile: Updated user profile + + Returns: + True if successful + """ + pass + + async def index_document(self, + document: Document, + user_id: Optional[str] = None) -> str: + """Index a document (essay, resume, etc.) into the system + + Args: + document: Document to index + user_id: User who owns the document (if applicable) + + Returns: + Document ID + """ + pass + + async def get_statistics(self, user_id: str) -> Dict[str, Any]: + """Get statistics about user's applications and system usage + + Args: + user_id: User ID + + Returns: + Statistics dictionary + """ + pass + + async def shutdown(self): + """Gracefully shutdown RAG engine and cleanup resources""" + pass + + +# ============================================================================ +# CONFIGURATION +# ============================================================================ + +class RAGConfig: + """Configuration for RAG Engine""" + + @staticmethod + def from_env() -> Dict[str, Any]: + """Load configuration from environment variables + + Returns: + Configuration dictionary + """ + pass + + @staticmethod + def from_file(config_path: str) -> Dict[str, Any]: + """Load configuration from file + + Args: + config_path: Path to config file + + Returns: + Configuration dictionary + """ + pass + + @staticmethod + def validate(config: Dict[str, Any]) -> bool: + """Validate configuration + + Args: + config: Configuration to validate + + Returns: + True if valid + """ + pass + + +# ============================================================================ +# MAIN ENTRY POINT +# ============================================================================ + +async def main(): + """Main entry point for RAG Engine service""" + pass + + +if __name__ == "__main__": + pass \ No newline at end of file diff --git a/backend/services/rag_engine/server.py b/backend/services/rag_engine/server.py index 8dc2c8c..f5fa754 100644 --- a/backend/services/rag_engine/server.py +++ b/backend/services/rag_engine/server.py @@ -131,14 +131,6 @@ async def SemanticSearch(self, request, context): return top_matches -# SELECT id, title, description -# 1 - (embedding <=> %s::vector AS similarity) -# FROM opportunities -# WHERE id = ANY (%s) -# ORDER BY embedding <=> %s::vector -# LIMIT 100; - return {} - async def serve(host: str = "0.0.0.0", port: int = 50053): """Start the RAG Engine server""" diff --git a/backend/services/rag_engine/sql/insertUserDocument.sql b/backend/services/rag_engine/sql/insertUserDocument.sql new file mode 100644 index 0000000..8580349 --- /dev/null +++ b/backend/services/rag_engine/sql/insertUserDocument.sql @@ -0,0 +1 @@ +INSERT \ No newline at end of file diff --git a/backend/services/rag_engine/tdummy.py b/backend/services/rag_engine/tdummy.py new file mode 100644 index 0000000..eb78412 --- /dev/null +++ b/backend/services/rag_engine/tdummy.py @@ -0,0 +1,734 @@ +import pytest +import asyncio +from unittest.mock import Mock, AsyncMock, patch, MagicMock +from typing import List, Dict, Any +from dataclasses import asdict + +# Import the classes to test (assuming they're in rag_engine.py) +from rag_engine import ( + Document, Scholarship, UserProfile, RetrievalResult, RAGContext, + QueryType, VectorStore, EmbeddingService, RetrievalEngine, + ContextBuilder, LLMClient, ResponseProcessor, QueryClassifier, + RAGEngine, RAGConfig +) + + +# ============================================================================ +# FIXTURES +# ============================================================================ + +@pytest.fixture +def sample_document(): + return Document( + id="doc1", + content="This is a test document about scholarships.", + metadata={"type": "scholarship", "year": 2024}, + embedding=[0.1, 0.2, 0.3] + ) + + +@pytest.fixture +def sample_scholarship(): + return Scholarship( + id="sch1", + name="Test Scholarship", + organization="Test Org", + deadline="2024-12-31", + requirements=["GPA 3.5+", "Essay required"], + essay_prompts=["Why do you deserve this scholarship?"], + eligibility_criteria={"gpa": 3.5, "major": "Computer Science"}, + award_amount="$5000", + metadata={"category": "STEM"} + ) + + +@pytest.fixture +def sample_user_profile(): + return UserProfile( + user_id="user1", + resume="Software Engineer with 3 years experience", + transcripts=["Transcript 1", "Transcript 2"], + past_essays=[], + achievements=["Dean's List", "Hackathon Winner"], + personal_info={"gpa": 3.8, "major": "Computer Science"}, + metadata={"graduation_year": 2025} + ) + + +@pytest.fixture +def sample_retrieval_result(sample_document): + return RetrievalResult( + document=sample_document, + score=0.95, + rank=1 + ) + + +@pytest.fixture +def sample_rag_context(sample_retrieval_result, sample_user_profile, sample_scholarship): + return RAGContext( + retrieved_documents=[sample_retrieval_result], + user_profile=sample_user_profile, + scholarship_info=sample_scholarship, + conversation_history=[{"role": "user", "content": "Hello"}], + metadata={"session_id": "123"} + ) + + +@pytest.fixture +def mock_config(): + return { + "vector_store": {"connection_string": "test://localhost"}, + "embedding": {"model": "text-embedding-ada-002", "dimension": 1536}, + "retrieval": {"top_k": 5, "threshold": 0.7}, + "llm_manager_address": "localhost:50054", + "max_tokens": 4000 + } + + +# ============================================================================ +# VECTOR STORE TESTS +# ============================================================================ + +class TestVectorStore: + + @pytest.mark.asyncio + async def test_add_documents(self, mock_config, sample_document): + store = VectorStore(mock_config["vector_store"]) + store.add_documents = AsyncMock(return_value=["doc1"]) + + result = await store.add_documents([sample_document]) + + assert result == ["doc1"] + store.add_documents.assert_called_once() + + @pytest.mark.asyncio + async def test_update_document(self, mock_config, sample_document): + store = VectorStore(mock_config["vector_store"]) + store.update_document = AsyncMock(return_value=True) + + result = await store.update_document("doc1", sample_document) + + assert result is True + store.update_document.assert_called_once_with("doc1", sample_document) + + @pytest.mark.asyncio + async def test_delete_document(self, mock_config): + store = VectorStore(mock_config["vector_store"]) + store.delete_document = AsyncMock(return_value=True) + + result = await store.delete_document("doc1") + + assert result is True + store.delete_document.assert_called_once_with("doc1") + + @pytest.mark.asyncio + async def test_search(self, mock_config, sample_retrieval_result): + store = VectorStore(mock_config["vector_store"]) + store.search = AsyncMock(return_value=[sample_retrieval_result]) + + query_embedding = [0.1, 0.2, 0.3] + results = await store.search(query_embedding, top_k=5) + + assert len(results) == 1 + assert results[0].score == 0.95 + store.search.assert_called_once() + + @pytest.mark.asyncio + async def test_search_with_filters(self, mock_config, sample_retrieval_result): + store = VectorStore(mock_config["vector_store"]) + store.search = AsyncMock(return_value=[sample_retrieval_result]) + + filters = {"type": "scholarship"} + results = await store.search([0.1, 0.2, 0.3], top_k=3, filters=filters) + + assert len(results) == 1 + store.search.assert_called_once() + + @pytest.mark.asyncio + async def test_get_document(self, mock_config, sample_document): + store = VectorStore(mock_config["vector_store"]) + store.get_document = AsyncMock(return_value=sample_document) + + doc = await store.get_document("doc1") + + assert doc.id == "doc1" + assert doc.content == "This is a test document about scholarships." + + @pytest.mark.asyncio + async def test_get_document_not_found(self, mock_config): + store = VectorStore(mock_config["vector_store"]) + store.get_document = AsyncMock(return_value=None) + + doc = await store.get_document("nonexistent") + + assert doc is None + + +# ============================================================================ +# EMBEDDING SERVICE TESTS +# ============================================================================ + +class TestEmbeddingService: + + @pytest.mark.asyncio + async def test_embed_text(self, mock_config): + service = EmbeddingService(mock_config["embedding"]) + service.embed_text = AsyncMock(return_value=[0.1] * 1536) + + embedding = await service.embed_text("test text") + + assert len(embedding) == 1536 + assert all(isinstance(x, float) for x in embedding) + + @pytest.mark.asyncio + async def test_embed_batch(self, mock_config): + service = EmbeddingService(mock_config["embedding"]) + service.embed_batch = AsyncMock(return_value=[[0.1] * 1536, [0.2] * 1536]) + + embeddings = await service.embed_batch(["text1", "text2"]) + + assert len(embeddings) == 2 + assert len(embeddings[0]) == 1536 + + def test_get_embedding_dimension(self, mock_config): + service = EmbeddingService(mock_config["embedding"]) + service.get_embedding_dimension = Mock(return_value=1536) + + dimension = service.get_embedding_dimension() + + assert dimension == 1536 + + +# ============================================================================ +# RETRIEVAL ENGINE TESTS +# ============================================================================ + +class TestRetrievalEngine: + + @pytest.fixture + def mock_vector_store(self): + return Mock(spec=VectorStore) + + @pytest.fixture + def mock_embedding_service(self): + return Mock(spec=EmbeddingService) + + @pytest.fixture + def retrieval_engine(self, mock_vector_store, mock_embedding_service, mock_config): + return RetrievalEngine( + mock_vector_store, + mock_embedding_service, + mock_config["retrieval"] + ) + + @pytest.mark.asyncio + async def test_retrieve(self, retrieval_engine, sample_retrieval_result): + retrieval_engine.retrieve = AsyncMock(return_value=[sample_retrieval_result]) + + results = await retrieval_engine.retrieve( + "test query", + QueryType.GENERAL_QUESTION, + top_k=5 + ) + + assert len(results) == 1 + assert results[0].score == 0.95 + + @pytest.mark.asyncio + async def test_retrieve_scholarships(self, retrieval_engine, sample_user_profile, sample_scholarship): + retrieval_engine.retrieve_scholarships = AsyncMock(return_value=[sample_scholarship]) + + scholarships = await retrieval_engine.retrieve_scholarships(sample_user_profile) + + assert len(scholarships) == 1 + assert scholarships[0].name == "Test Scholarship" + + @pytest.mark.asyncio + async def test_retrieve_similar_essays(self, retrieval_engine, sample_document): + retrieval_engine.retrieve_similar_essays = AsyncMock(return_value=[sample_document]) + + essays = await retrieval_engine.retrieve_similar_essays( + "Why do you deserve this scholarship?", + "user1", + top_k=3 + ) + + assert len(essays) == 1 + assert essays[0].id == "doc1" + + @pytest.mark.asyncio + async def test_hybrid_search(self, retrieval_engine, sample_retrieval_result): + retrieval_engine.hybrid_search = AsyncMock(return_value=[sample_retrieval_result]) + + results = await retrieval_engine.hybrid_search( + "test query", + top_k=5, + alpha=0.5 + ) + + assert len(results) == 1 + retrieval_engine.hybrid_search.assert_called_once() + + +# ============================================================================ +# CONTEXT BUILDER TESTS +# ============================================================================ + +class TestContextBuilder: + + @pytest.fixture + def context_builder(self, mock_config): + return ContextBuilder(mock_config) + + @pytest.mark.asyncio + async def test_build_context(self, context_builder, sample_retrieval_result, + sample_user_profile, sample_scholarship): + context_builder.build_context = AsyncMock(return_value=RAGContext( + retrieved_documents=[sample_retrieval_result], + user_profile=sample_user_profile, + scholarship_info=sample_scholarship, + conversation_history=[], + metadata={} + )) + + context = await context_builder.build_context( + "test query", + QueryType.ESSAY_GENERATION, + [sample_retrieval_result], + sample_user_profile, + sample_scholarship + ) + + assert context.user_profile.user_id == "user1" + assert context.scholarship_info.name == "Test Scholarship" + + def test_format_prompt(self, context_builder, sample_rag_context): + context_builder.format_prompt = Mock(return_value="Formatted prompt") + + prompt = context_builder.format_prompt(sample_rag_context, "test query") + + assert isinstance(prompt, str) + assert len(prompt) > 0 + + def test_estimate_tokens(self, context_builder): + context_builder.estimate_tokens = Mock(return_value=100) + + token_count = context_builder.estimate_tokens("This is a test string") + + assert token_count == 100 + + def test_truncate_to_token_limit(self, context_builder): + long_text = "word " * 1000 + context_builder.truncate_to_token_limit = Mock(return_value="word " * 50) + + truncated = context_builder.truncate_to_token_limit(long_text, 100) + + assert len(truncated) < len(long_text) + + +# ============================================================================ +# LLM CLIENT TESTS +# ============================================================================ + +class TestLLMClient: + + @pytest.fixture + def llm_client(self): + return LLMClient("localhost:50054") + + @pytest.mark.asyncio + async def test_generate_completion(self, llm_client): + llm_client.generate_completion = AsyncMock(return_value={ + "content": "Generated text", + "usage": {"prompt_tokens": 100, "completion_tokens": 50}, + "model": "gpt-4" + }) + + response = await llm_client.generate_completion( + "Test prompt", + temperature=0.7, + max_tokens=1000 + ) + + assert "content" in response + assert response["content"] == "Generated text" + assert "usage" in response + + @pytest.mark.asyncio + async def test_stream_completion(self, llm_client): + async def mock_stream(): + yield {"content": "chunk1"} + yield {"content": "chunk2"} + + llm_client.stream_completion = mock_stream + + chunks = [] + async for chunk in llm_client.stream_completion("Test prompt"): + chunks.append(chunk) + + assert len(chunks) == 2 + assert chunks[0]["content"] == "chunk1" + + +# ============================================================================ +# RESPONSE PROCESSOR TESTS +# ============================================================================ + +class TestResponseProcessor: + + @pytest.fixture + def processor(self, mock_config): + return ResponseProcessor(mock_config) + + @pytest.mark.asyncio + async def test_process_essay_response(self, processor, sample_scholarship): + processor.process_essay_response = AsyncMock(return_value={ + "essay": "Processed essay text", + "word_count": 500, + "validation": {"is_valid": True} + }) + + result = await processor.process_essay_response( + "Essay text", + sample_scholarship + ) + + assert "essay" in result + assert result["validation"]["is_valid"] is True + + @pytest.mark.asyncio + async def test_validate_word_count_valid(self, processor): + processor.validate_word_count = AsyncMock(return_value=(True, 500)) + + is_valid, count = await processor.validate_word_count( + "word " * 500, + 400, + 600 + ) + + assert is_valid is True + assert count == 500 + + @pytest.mark.asyncio + async def test_validate_word_count_invalid(self, processor): + processor.validate_word_count = AsyncMock(return_value=(False, 300)) + + is_valid, count = await processor.validate_word_count( + "word " * 300, + 400, + 600 + ) + + assert is_valid is False + assert count == 300 + + @pytest.mark.asyncio + async def test_extract_structured_data(self, processor): + schema = {"name": "str", "age": "int"} + processor.extract_structured_data = AsyncMock(return_value={ + "name": "John Doe", + "age": 25 + }) + + result = await processor.extract_structured_data( + "Response text with data", + schema + ) + + assert result["name"] == "John Doe" + assert result["age"] == 25 + + @pytest.mark.asyncio + async def test_fact_check(self, processor, sample_document): + processor.fact_check = AsyncMock(return_value={ + "is_verified": True, + "confidence": 0.95, + "evidence": ["doc1"] + }) + + result = await processor.fact_check( + "This is a claim", + [sample_document] + ) + + assert result["is_verified"] is True + assert result["confidence"] == 0.95 + + +# ============================================================================ +# QUERY CLASSIFIER TESTS +# ============================================================================ + +class TestQueryClassifier: + + @pytest.fixture + def classifier(self, mock_config): + return QueryClassifier(mock_config) + + @pytest.mark.asyncio + async def test_classify_scholarship_search(self, classifier): + classifier.classify = AsyncMock(return_value=QueryType.SCHOLARSHIP_SEARCH) + + query_type = await classifier.classify("Find scholarships for computer science") + + assert query_type == QueryType.SCHOLARSHIP_SEARCH + + @pytest.mark.asyncio + async def test_classify_essay_generation(self, classifier): + classifier.classify = AsyncMock(return_value=QueryType.ESSAY_GENERATION) + + query_type = await classifier.classify("Write an essay about my achievements") + + assert query_type == QueryType.ESSAY_GENERATION + + @pytest.mark.asyncio + async def test_extract_intent(self, classifier): + classifier.extract_intent = AsyncMock(return_value={ + "action": "search", + "entities": ["computer science", "stem"], + "filters": {"major": "Computer Science"} + }) + + intent = await classifier.extract_intent("Find STEM scholarships") + + assert intent["action"] == "search" + assert "computer science" in intent["entities"] + + +# ============================================================================ +# RAG ENGINE TESTS +# ============================================================================ + +class TestRAGEngine: + + @pytest.fixture + def rag_engine(self, mock_config): + return RAGEngine(mock_config) + + @pytest.mark.asyncio + async def test_initialize(self, rag_engine): + rag_engine.initialize = AsyncMock() + + await rag_engine.initialize() + + rag_engine.initialize.assert_called_once() + + @pytest.mark.asyncio + async def test_query(self, rag_engine): + rag_engine.query = AsyncMock(return_value={ + "answer": "This is the answer", + "sources": ["doc1", "doc2"], + "metadata": {"query_type": "general_question"} + }) + + response = await rag_engine.query( + "What is the deadline?", + "user1" + ) + + assert "answer" in response + assert len(response["sources"]) == 2 + + @pytest.mark.asyncio + async def test_generate_essay(self, rag_engine): + rag_engine.generate_essay = AsyncMock(return_value={ + "essay": "Generated essay content", + "word_count": 500, + "validation": {"is_valid": True} + }) + + result = await rag_engine.generate_essay( + "sch1", + "user1", + "Why do you deserve this scholarship?" + ) + + assert "essay" in result + assert result["validation"]["is_valid"] is True + + @pytest.mark.asyncio + async def test_check_eligibility(self, rag_engine): + rag_engine.check_eligibility = AsyncMock(return_value={ + "eligible": True, + "explanation": "Meets all requirements", + "requirements_met": ["GPA", "Major"] + }) + + result = await rag_engine.check_eligibility("sch1", "user1") + + assert result["eligible"] is True + assert len(result["requirements_met"]) == 2 + + @pytest.mark.asyncio + async def test_search_scholarships(self, rag_engine, sample_scholarship): + rag_engine.search_scholarships = AsyncMock(return_value=[sample_scholarship]) + + scholarships = await rag_engine.search_scholarships( + "user1", + query="STEM scholarships", + top_k=10 + ) + + assert len(scholarships) == 1 + assert scholarships[0].name == "Test Scholarship" + + @pytest.mark.asyncio + async def test_add_scholarship(self, rag_engine, sample_scholarship): + rag_engine.add_scholarship = AsyncMock(return_value="sch1") + + scholarship_id = await rag_engine.add_scholarship(sample_scholarship) + + assert scholarship_id == "sch1" + + @pytest.mark.asyncio + async def test_update_user_profile(self, rag_engine, sample_user_profile): + rag_engine.update_user_profile = AsyncMock(return_value=True) + + result = await rag_engine.update_user_profile(sample_user_profile) + + assert result is True + + @pytest.mark.asyncio + async def test_index_document(self, rag_engine, sample_document): + rag_engine.index_document = AsyncMock(return_value="doc1") + + doc_id = await rag_engine.index_document(sample_document, "user1") + + assert doc_id == "doc1" + + @pytest.mark.asyncio + async def test_get_statistics(self, rag_engine): + rag_engine.get_statistics = AsyncMock(return_value={ + "applications": 5, + "essays_generated": 10, + "scholarships_searched": 20 + }) + + stats = await rag_engine.get_statistics("user1") + + assert stats["applications"] == 5 + assert stats["essays_generated"] == 10 + + @pytest.mark.asyncio + async def test_shutdown(self, rag_engine): + rag_engine.shutdown = AsyncMock() + + await rag_engine.shutdown() + + rag_engine.shutdown.assert_called_once() + + +# ============================================================================ +# RAG CONFIG TESTS +# ============================================================================ + +class TestRAGConfig: + + def test_from_env(self): + with patch.dict('os.environ', { + 'VECTOR_STORE_URL': 'test://localhost', + 'LLM_MANAGER_ADDRESS': 'localhost:50054' + }): + RAGConfig.from_env = Mock(return_value={ + "vector_store": {"url": "test://localhost"}, + "llm_manager_address": "localhost:50054" + }) + + config = RAGConfig.from_env() + + assert config["vector_store"]["url"] == "test://localhost" + + def test_from_file(self): + RAGConfig.from_file = Mock(return_value={ + "vector_store": {"url": "test://localhost"} + }) + + config = RAGConfig.from_file("config.yaml") + + assert "vector_store" in config + + def test_validate_valid_config(self, mock_config): + RAGConfig.validate = Mock(return_value=True) + + is_valid = RAGConfig.validate(mock_config) + + assert is_valid is True + + def test_validate_invalid_config(self): + RAGConfig.validate = Mock(return_value=False) + + is_valid = RAGConfig.validate({}) + + assert is_valid is False + + +# ============================================================================ +# DATA MODEL TESTS +# ============================================================================ + +class TestDataModels: + + def test_document_creation(self, sample_document): + assert sample_document.id == "doc1" + assert sample_document.content == "This is a test document about scholarships." + assert sample_document.metadata["type"] == "scholarship" + + def test_scholarship_creation(self, sample_scholarship): + assert sample_scholarship.id == "sch1" + assert sample_scholarship.name == "Test Scholarship" + assert len(sample_scholarship.requirements) == 2 + + def test_user_profile_creation(self, sample_user_profile): + assert sample_user_profile.user_id == "user1" + assert sample_user_profile.personal_info["gpa"] == 3.8 + + def test_retrieval_result_creation(self, sample_retrieval_result): + assert sample_retrieval_result.score == 0.95 + assert sample_retrieval_result.rank == 1 + + def test_rag_context_creation(self, sample_rag_context): + assert len(sample_rag_context.retrieved_documents) == 1 + assert sample_rag_context.user_profile.user_id == "user1" + + def test_query_type_enum(self): + assert QueryType.SCHOLARSHIP_SEARCH.value == "scholarship_search" + assert QueryType.ESSAY_GENERATION.value == "essay_generation" + + +# ============================================================================ +# INTEGRATION TESTS +# ============================================================================ + +class TestIntegration: + + @pytest.mark.asyncio + async def test_full_query_flow(self, mock_config): + # This would test the full flow from query to response + rag_engine = RAGEngine(mock_config) + rag_engine.initialize = AsyncMock() + rag_engine.query = AsyncMock(return_value={ + "answer": "Test answer", + "sources": ["doc1"] + }) + + await rag_engine.initialize() + response = await rag_engine.query("test query", "user1") + + assert response["answer"] == "Test answer" + + @pytest.mark.asyncio + async def test_essay_generation_flow(self, mock_config): + rag_engine = RAGEngine(mock_config) + rag_engine.generate_essay = AsyncMock(return_value={ + "essay": "Generated essay", + "validation": {"is_valid": True} + }) + + result = await rag_engine.generate_essay("sch1", "user1", "Essay prompt") + + assert result["validation"]["is_valid"] is True + + +if __name__ == "__main__": + pytest.main([__file__, "-v"]) \ No newline at end of file diff --git a/backend/services/rag_engine/tests/test.py b/backend/services/rag_engine/tests/test.py new file mode 100644 index 0000000..6b22ce9 --- /dev/null +++ b/backend/services/rag_engine/tests/test.py @@ -0,0 +1,124 @@ +#NOTE: may have to run docker container before starting anything + +import pytest +import pytest_asyncio +import psycopg2 +import datetime +from unittest.mock import Mock, AsyncMock, patch, MagicMock +from datetime import datetime +from typing import List, Dict, Any +from dataclasses import asdict +from pathlib import Path +from langchain_community.embeddings import HuggingFaceEmbeddings +from langchain_community.vectorstores.pgvector import PGVector +import os +from sqlalchemy import create_engine, text +from reportlab.pdfgen import canvas + +import sys +from pathlib import Path + +# Add project root to Python path to fix imports +project_root = Path(__file__).parent.parent.parent.parent.parent +if str(project_root) not in sys.path: + sys.path.insert(0, str(project_root)) + +import asyncio +import grpc +from google.protobuf import struct_pb2 +from backend.generated import rag_engine_pb2_grpc, rag_engine_pb2 + +# Import the classes to test (assuming they're in rag_engine.py) +from backend.services.rag_engine.core.rag import VectorDBService, User, Scholarship +from backend.generated.rag_engine_pb2_grpc import VectorDBServiceServicer + +models_folder = "./../../../db/models" +db_folder = "./../../../db" + +#probably change 50053 to env variable or random later down the line +@pytest_asyncio.fixture +async def grpc_server(): + server = grpc.aio.server() + servicer = VectorDBService() + rag_engine_pb2_grpc.add_VectorDBServiceServicer_to_server(servicer, server) + port = server.add_insecure_port(f"[::]:0") + await server.start() + + print(f"Server started on port {port}") + yield f"localhost:{port}" + await server.stop(grace=0) + +#accompanying method: + # async def Init(self, request:rag_engine_pb2.InitRequest, + # context: grpc.aio.ServicerContext) -> rag_engine_pb2.InitResponse: + # try: + # connection_string = request.connection_string + # collection_name = request.collection_name + # self.engine = PGEngine.from_connection_string( + # url = connection_string, + # pool_size=5, + # max_overflow=10 + # ) + # self.vs = PGVector( + # connection=connection_string, + # collection_name=collection_name, + # embeddings=self.embeddings, + # distance_strategy=DistanceStrategy.COSINE, + # async_mode=True + # ) + # self.retriever = self.vs.as_retriever() + # logs.info("VectorDB Service Initialized Successfully") + # return rag_engine_pb2.InitResponse(success = True) + # except Exception as e: + # logs.error(f"Error During Init: {e}") + # return rag_engine_pb2.InitResponse(error = e) +@pytest.mark.asyncio +async def test_vector_db_init(grpc_server): + channel = grpc.aio.insecure_channel(grpc_server) + stub = rag_engine_pb2_grpc.VectorDBServiceStub(channel) + + request = rag_engine_pb2.InitRequest( + connection_string="postgresql+asyncpg://postgres:postgres@localhost:5432/vectordb", + collection_name="user_docs" + ) + print("About to call func!!") + response = await stub.Init(request) + assert response is not None + print("Response for VectorDBService Init:", response) + +@pytest.mark.asyncio +async def test_embed_scholarship_batch(grpc_server): + print("\n" + "="*60) + print("TEST: Embed Scholarship batch") + print("="*60) + + channel = grpc.aio.insecure_channel(grpc_server) + await channel.channel_ready() + print(f"Connected to {channel}") + stub = rag_engine_pb2_grpc.VectorDBServiceStub(channel) + print(f"stub at {stub}") + + try: + + request = rag_engine_pb2.EmbedScholarshipBatchRequest( + scholarships=[ + rag_engine_pb2.Scholarship( + name="Test Scholarship", + min_gpa=3.5, + eligible_majors=["CS", "EE"], + description="A test scholarship" + ) + ] + ) + + response = await asyncio.wait_for(stub.EmbedScholarshipBatch(request), timeout=5) + print("Response for VectorDBService EmbedScholarshipBatch: ", response) + + assert response.count == len(request.scholarships) + except Exception as e: + print(f"Error: {e}") + finally: + await channel.close() + +if __name__ == "__main__": + pytest.main([__file__, "-v"]) \ No newline at end of file diff --git a/db/Dockerfile b/db/Dockerfile index 2cc86da..82d1bae 100644 --- a/db/Dockerfile +++ b/db/Dockerfile @@ -1 +1,46 @@ -# DB Dockerfile here +# Use PostgreSQL Alpine image for smaller footprint +FROM postgres:17-alpine3.22 + +# Install build dependencies for extensions +RUN apk add --no-cache \ + git \ + build-base \ + clang \ + llvm \ + postgresql-dev + +# Install pgvector extension +# Using v0.8.0 which is compatible with PostgreSQL 17 +# Skip LLVM bitcode generation with with_llvm=no +RUN cd /tmp && \ + git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git && \ + cd pgvector && \ + make clean && \ + make OPTFLAGS="" with_llvm=no && \ + make install with_llvm=no && \ + cd / && \ + rm -rf /tmp/pgvector + +# Clean up build dependencies to reduce image size +RUN apk del git build-base clang llvm + +# Note: Initialization scripts are mounted via volume in docker-compose.yml +# Scripts in /docker-entrypoint-initdb.d/ are executed in alphabetical order: +# - init.sql (extensions and config) +# - fiapply.sql (schema) + +# Set environment variables with sensible defaults +ENV POSTGRES_DB=fiapply +ENV POSTGRES_USER=fiapply_user +ENV POSTGRES_PASSWORD=fiapply_password +ENV PGDATA=/var/lib/postgresql/data/pgdata + +# Expose PostgreSQL port +EXPOSE 5432 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ + CMD pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB} || exit 1 + +# Use the default PostgreSQL entrypoint +# which handles initialization and starts the server diff --git a/db/README.md b/db/README.md new file mode 100644 index 0000000..97dc4b1 --- /dev/null +++ b/db/README.md @@ -0,0 +1,340 @@ +# FiApply Database - PostgreSQL + +This directory contains the PostgreSQL database schema, migrations, and configuration for the FiApply application. + +## Overview + +The database uses **PostgreSQL 17-alpine3.22** for a lightweight, production-ready setup with the following extensions: + +- **pgvector** - Vector similarity search for ML/AI embeddings (384-dimensional vectors) +- **pg_stat_statements** - Query performance monitoring and optimization +- **pg_trgm** - Trigram-based fuzzy text search + +## Directory Structure + +```zsh +db/ +โ”œโ”€โ”€ Dockerfile # PostgreSQL container with extensions +โ”œโ”€โ”€ init.sql # Extension initialization and database setup +โ”œโ”€โ”€ fiapply.sql # Complete database schema +โ”œโ”€โ”€ models/ # Individual table definitions +โ”‚ โ”œโ”€โ”€ references.sql # Lookup tables (countries, majors, skills) +โ”‚ โ”œโ”€โ”€ users.sql # User profiles and preferences +โ”‚ โ”œโ”€โ”€ opportunities.sql # Opportunities and requirements +โ”‚ โ”œโ”€โ”€ matches.sql # Matching/analytics tables +โ”‚ โ””โ”€โ”€ indicies.sql # Performance indexes +โ””โ”€โ”€ retrieval/ + โ””โ”€โ”€ rag.sql # RAG-specific queries and notes +``` + +## Quick Start + +### Using Docker Compose + +```zsh +# Start PostgreSQL database +docker-compose up postgres + +# Start with pgAdmin (web UI) +docker-compose --profile tools up postgres pgadmin + +# View logs +docker-compose logs -f postgres +``` + +### Accessing the Database + +**From Host Machine:** + +```zsh +psql -h localhost -p 5432 -U fiapply_user -d fiapply +# Password: fiapply_password +``` + +**From Docker Container:** + +```zsh +docker exec -it fi-postgres psql -U fiapply_user -d fiapply +``` + +**Using pgAdmin:** + +- URL: http://localhost:5050 +- Email: admin@fiapply.local +- Password: admin + +### Environment Variables + +Copy `.env.example` to `.env` and update with your credentials: + +```zsh +cp .env.example .env +``` + +## Database Schema + +### Core Tables + +**Reference Tables:** + +- `countries`, `states_provinces`, `cities`, `addresses` - Geographic data +- `majors`, `citizenship_types`, `grade_levels` - Academic references +- `skills`, `interests` - User/opportunity attributes +- `organizations` - Opportunity providers + +**User Tables:** + +- `user_profiles` - User accounts and academic info +- `user_skills`, `user_interests` - User attributes (many-to-many) +- `user_preferred_types`, `user_preferred_locations` - User preferences + +**Opportunity Tables:** + +- `opportunities` - Scholarships, internships, jobs +- `opportunity_document_chunks` - Chunked text with embeddings for RAG +- `opportunity_majors`, `opportunity_citizenship`, etc. - Eligibility criteria (many-to-many) + +**Matching/Analytics Tables:** + +- `match_results` - Cached matching scores +- `search_queries` - Search history with embeddings +- `user_applications` - Application tracking + +### Key Features + +**Vector Search (pgvector):** + +- 384-dimensional embeddings using `sentence-transformers/all-MiniLM-L6-v2` +- HNSW indexes for fast approximate nearest neighbor search +- Cosine similarity for semantic matching + +**Fuzzy Text Search (pg_trgm):** + +- Trigram-based similarity for fuzzy matching +- GIN indexes on titles, descriptions, names +- Supports typo-tolerant search + +**Performance Indexes:** + +- B-tree indexes on foreign keys and filter columns +- HNSW indexes on vector columns +- GIN indexes on text columns +- Partial indexes for active/upcoming opportunities + +## Extensions + +### pgvector + +**Installation:** +Built from source (v0.7.4) during Docker image build. + +**Usage:** + +```sql +-- Store embeddings +INSERT INTO user_profiles (username, resume_embedding) +VALUES ('john', '[0.1, 0.2, ..., 0.384]'::vector(384)); + +-- Similarity search +SELECT username, + 1 - (resume_embedding <=> query_embedding) as similarity +FROM user_profiles +ORDER BY resume_embedding <=> query_embedding +LIMIT 10; +``` + +**Operators:** + +- `<->` - Euclidean distance (L2) +- `<#>` - Negative inner product +- `<=>` - Cosine distance + +### pg_stat_statements + +**View Query Statistics:** + +```sql +SELECT query, calls, total_exec_time, mean_exec_time +FROM pg_stat_statements +ORDER BY total_exec_time DESC +LIMIT 10; +``` + +### pg_trgm + +**Fuzzy Search:** + +```sql +-- Find similar titles +SELECT title, similarity(title, 'software engineer') as sim +FROM opportunities +WHERE title % 'software engineer' -- % operator for similarity match +ORDER BY sim DESC; +``` + +## Maintenance + +### Backup Database + +```zsh +# Backup all data +docker exec fi-postgres pg_dump -U fiapply_user fiapply > backup.sql + +# Backup schema only +docker exec fi-postgres pg_dump -U fiapply_user --schema-only fiapply > schema.sql +``` + +### Restore Database + +```zsh +# Restore from backup +docker exec -i fi-postgres psql -U fiapply_user fiapply < backup.sql +``` + +### Refresh Materialized Views + +```sql +REFRESH MATERIALIZED VIEW opportunity_stats; +``` + +### Update Statistics + +```sql +ANALYZE; -- Update all table statistics +VACUUM ANALYZE opportunities; -- Vacuum and analyze specific table +``` + +### Monitor Performance + +```sql +-- Check index usage +SELECT schemaname, tablename, indexname, idx_scan +FROM pg_stat_user_indexes +ORDER BY idx_scan; + +-- Check table sizes +SELECT tablename, + pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size +FROM pg_tables +WHERE schemaname = 'public' +ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC; +``` + +## Development + +### Schema Changes + +1. Modify the appropriate SQL file in `models/` +2. Update `fiapply.sql` if adding new files +3. Rebuild the database: + + ```zsh + docker-compose down -v postgres # Remove old data + docker-compose up postgres # Recreate with new schema + ``` + +### Testing Queries + +```zsh +# Connect to database +docker exec -it fi-postgres psql -U fiapply_user -d fiapply + +# Run test queries +\d user_profiles # Describe table +\di # List indexes +SELECT * FROM health_check; # Health check +``` + +## Troubleshooting + +### Database won't start + +```zsh +# Check logs +docker-compose logs postgres + +# Reset database (WARNING: deletes all data) +docker-compose down -v postgres +docker volume rm fiapply_postgres-data +docker-compose up postgres +``` + +### Connection refused + +```zsh +# Check if container is running +docker ps | grep postgres + +# Check health status +docker inspect fi-postgres | grep -A 10 Health + +# Test connection +docker exec fi-postgres pg_isready -U fiapply_user -d fiapply +``` + +### Extensions not loading + +```zsh +# Check installed extensions +docker exec -it fi-postgres psql -U fiapply_user -d fiapply -c "\dx" + +# Manually create extension (if needed) +docker exec -it fi-postgres psql -U fiapply_user -d fiapply -c "CREATE EXTENSION IF NOT EXISTS vector;" +``` + +### Performance issues + +```sql +-- Check slow queries +SELECT query, calls, mean_exec_time +FROM pg_stat_statements +WHERE mean_exec_time > 1000 -- > 1 second +ORDER BY mean_exec_time DESC; + +-- Check missing indexes +SELECT schemaname, tablename, attname +FROM pg_stats +WHERE correlation < 0.5 +AND n_distinct > 1000; +``` + +## Production Considerations + +### Security + +- [ ] Change default passwords in `.env` +- [ ] Use secrets management (Docker secrets, Vault, etc.) +- [ ] Enable SSL/TLS connections +- [ ] Restrict network access (firewall rules) +- [ ] Regular security updates + +### Performance + +- [ ] Tune `shared_buffers`, `work_mem`, `maintenance_work_mem` +- [ ] Configure connection pooling (PgBouncer, pgpool) +- [ ] Monitor with pg_stat_statements +- [ ] Regular VACUUM and ANALYZE +- [ ] Archive old data + +### Backup Strategy + +- [ ] Automated daily backups +- [ ] Point-in-time recovery (WAL archiving) +- [ ] Test restore procedures +- [ ] Off-site backup storage +- [ ] Backup retention policy + +### Monitoring + +- [ ] Set up monitoring (Prometheus, Grafana, pgwatch2) +- [ ] Alert on disk space +- [ ] Alert on connection limits +- [ ] Alert on replication lag (if using replication) +- [ ] Monitor query performance + +## Resources + +- [PostgreSQL Documentation](https://www.postgresql.org/docs/) +- [pgvector Documentation](https://github.com/pgvector/pgvector) +- [pg_trgm Documentation](https://www.postgresql.org/docs/current/pgtrgm.html) +- [pg_stat_statements Documentation](https://www.postgresql.org/docs/current/pgstatstatements.html) diff --git a/db/fiapply.sql b/db/fiapply.sql new file mode 100644 index 0000000..43568dc --- /dev/null +++ b/db/fiapply.sql @@ -0,0 +1,474 @@ +-- ============================================================================ +-- FiApply Database Schema +-- ============================================================================ +-- PostgreSQL database schema for FiApply application +-- +-- This file orchestrates the creation of all database objects in the correct order +-- Prerequisites: Extensions must be initialized via init.sql first +-- +-- Schema Organization: +-- 1. Reference/Lookup Tables (countries, majors, skills, etc.) +-- 2. Core Entity Tables (users, opportunities, organizations) +-- 3. Relationship/Junction Tables (user_skills, opportunity_majors, etc.) +-- 4. Analytics/Matching Tables (match_results, search_queries, etc.) +-- 5. Indexes for Performance +-- ============================================================================ + +-- ============================================================================ +-- SECTION 1: REFERENCE/LOOKUP TABLES +-- ============================================================================ +-- Source: models/references.sql +-- These tables must be created first as they're referenced by other tables + +\echo 'Creating reference tables...' + +-- Geographic reference tables +CREATE TABLE IF NOT EXISTS countries ( + id SERIAL PRIMARY KEY, + code TEXT UNIQUE NOT NULL, -- ISO 3166-1 alpha-2 (US, CA, GB, etc) + name TEXT UNIQUE NOT NULL, + has_states BOOLEAN DEFAULT TRUE -- FALSE for monaco, singapore, vatican city (!!) +); + +CREATE TABLE IF NOT EXISTS states_provinces ( + id SERIAL PRIMARY KEY, + country_id INTEGER REFERENCES countries(id), + code TEXT NOT NULL, --e.g TX, CA, ON, etc + name TEXT NOT NULL, + type TEXT, -- state, province, unincorporated territority, territory, etc + UNIQUE (country_id, code) +); + +CREATE TABLE IF NOT EXISTS cities ( + id SERIAL PRIMARY KEY, + state_province_id INTEGER REFERENCES states_provinces(id), + country_id INTEGER REFERENCES countries(id), + name TEXT NOT NULL, + UNIQUE(country_id, state_province_id, name), + + CONSTRAINT city_valid CHECK ( + (country_id IS NOT NULL) + ) +); + +CREATE TABLE IF NOT EXISTS addresses( + id SERIAL PRIMARY KEY, + street_address TEXT, + city_id INTEGER REFERENCES cities(id), + state_province_id INTEGER REFERENCES states_provinces(id), + country_id INTEGER NOT NULL REFERENCES countries(id), + postal_code TEXT, + + latitude DECIMAL(10, 8), + longitude DECIMAL(11, 8), + + raw_address TEXT +); + +-- Academic and profile reference tables +CREATE TABLE IF NOT EXISTS majors ( + id SERIAL PRIMARY KEY, + name TEXT UNIQUE NOT NULL, + category TEXT --this can be like medicine, engineering, arts, sciences, business, etc +); + +CREATE TABLE IF NOT EXISTS citizenship_types( + id SERIAL PRIMARY KEY, + name TEXT UNIQUE NOT NULL -- 'US Citizen', 'Permanent Resident', 'International', etc +); + +CREATE TABLE IF NOT EXISTS grade_levels ( + id SERIAL PRIMARY KEY, + name TEXT UNIQUE NOT NULL, --freshman, soph, etc + sort_order INTEGER -- 1 = freshman, 2 = sophomore, etc +); + +CREATE TABLE IF NOT EXISTS skills ( + id SERIAL PRIMARY KEY, + name TEXT UNIQUE NOT NULL, + category TEXT -- e.g Programming, Design, Communication, Leadership, Entrepreneurship, etc +); + +CREATE TABLE IF NOT EXISTS interests ( + id SERIAL PRIMARY KEY, + name TEXT UNIQUE NOT NULL +); + +CREATE TABLE IF NOT EXISTS organizations ( + id SERIAL PRIMARY KEY, + name TEXT UNIQUE NOT NULL, + website TEXT, + description TEXT, + headquarters_address_id INTEGER REFERENCES addresses(id), + mailing_address_id INTEGER REFERENCES addresses(id) +); + +\echo 'Reference tables created successfully.' + +-- ============================================================================ +-- SECTION 2: USER TABLES +-- ============================================================================ +-- Source: models/users.sql + +\echo 'Creating user tables...' + +CREATE TABLE IF NOT EXISTS user_profiles ( + id SERIAL PRIMARY KEY, + username TEXT UNIQUE NOT NULL, + email TEXT NOT NULL UNIQUE, + + -- Academic Info + gpa DECIMAL(3,2), + major_id INTEGER REFERENCES majors(id), + grade_level_id INTEGER REFERENCES grade_levels(id), + graduate_date DATE, + university TEXT, + + -- Personal Info + citizenship_id INTEGER REFERENCES citizenship_types(id), + location TEXT, + + -- Resume and background + resume_text TEXT, + resume_embedding vector(384), + career_goals TEXT, + career_goals_embedding vector(384), + + -- Preferences + min_award_amount DECIMAL(10,2), + min_salary_amount DECIMAL(10,2), + + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Trigger to auto-update updated_at timestamp +CREATE TRIGGER update_user_profiles_updated_at + BEFORE UPDATE ON user_profiles + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +-- User relationship tables +CREATE TABLE IF NOT EXISTS user_skills ( + user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + skill_id INTEGER REFERENCES skills(id) ON DELETE CASCADE, + proficiency_level TEXT, + years_experience DECIMAL(3,1), + PRIMARY KEY(user_id, skill_id) +); + +CREATE TABLE IF NOT EXISTS user_interests ( + user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + interest_id INTEGER REFERENCES interests(id) ON DELETE CASCADE, + PRIMARY KEY(user_id, interest_id) +); + +CREATE TABLE IF NOT EXISTS user_preferred_types ( + user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + opportunity_type TEXT CHECK (opportunity_type IN ('scholarship', 'internship', 'job')), + PRIMARY KEY(user_id, opportunity_type) +); + +CREATE TABLE IF NOT EXISTS user_preferred_locations ( + id SERIAL PRIMARY KEY, + user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + location TEXT NOT NULL, + is_flexible BOOLEAN DEFAULT FALSE +); + +\echo 'User tables created successfully.' + +-- ============================================================================ +-- SECTION 3: OPPORTUNITY TABLES +-- ============================================================================ +-- Source: models/opportunities.sql + +\echo 'Creating opportunity tables...' + +CREATE TABLE IF NOT EXISTS opportunities ( + id SERIAL PRIMARY KEY, + title TEXT NOT NULL, + organization_id INTEGER REFERENCES organizations(id), + type TEXT CHECK (type IN ('scholarship', 'internship', 'job')), + description TEXT, + full_text TEXT, + + -- GPA requirements + min_gpa DECIMAL(3,2), + max_gpa DECIMAL(3,2), + + -- Application Details + deadline TIMESTAMP, + award_amount DECIMAL(10,2), + salary_min DECIMAL(10,2), + salary_max DECIMAL(10,2), + location TEXT, + is_remote BOOLEAN DEFAULT FALSE, + + -- Metadata + source_url TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_active BOOLEAN DEFAULT TRUE +); + +-- Trigger to auto-update updated_at timestamp +CREATE TRIGGER update_opportunities_updated_at + BEFORE UPDATE ON opportunities + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +-- Document chunks for RAG/semantic search +CREATE TABLE IF NOT EXISTS opportunity_document_chunks ( + id SERIAL PRIMARY KEY, + opportunity_id INTEGER REFERENCES opportunities(id) ON DELETE CASCADE, + chunk_text TEXT NOT NULL, + chunk_type TEXT, + chunk_index INTEGER, + embedding vector(384), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Opportunity relationship tables (many-to-many) +CREATE TABLE IF NOT EXISTS opportunity_majors ( + opportunity_id INTEGER REFERENCES opportunities(id) ON DELETE CASCADE, + major_id INTEGER REFERENCES majors(id) ON DELETE CASCADE, + PRIMARY KEY(opportunity_id, major_id) +); + +CREATE TABLE IF NOT EXISTS opportunity_citizenship ( + opportunity_id INTEGER REFERENCES opportunities(id) ON DELETE CASCADE, + citizenship_id INTEGER REFERENCES citizenship_types(id) ON DELETE CASCADE, + PRIMARY KEY (opportunity_id, citizenship_id) +); + +CREATE TABLE IF NOT EXISTS opportunity_grade_levels ( + opportunity_id INTEGER REFERENCES opportunities(id) ON DELETE CASCADE, + grade_level_id INTEGER REFERENCES grade_levels(id) ON DELETE CASCADE, + PRIMARY KEY (opportunity_id, grade_level_id) +); + +CREATE TABLE IF NOT EXISTS opportunity_skills ( + opportunity_id INTEGER REFERENCES opportunities(id) ON DELETE CASCADE, + skill_id INTEGER REFERENCES skills(id) ON DELETE CASCADE, + is_required BOOLEAN DEFAULT FALSE, + PRIMARY KEY (opportunity_id, skill_id) +); + +CREATE TABLE IF NOT EXISTS opportunity_interests ( + opportunity_id INTEGER REFERENCES opportunities(id) ON DELETE CASCADE, + interest_id INTEGER REFERENCES interests(id) ON DELETE CASCADE, + PRIMARY KEY (opportunity_id, interest_id) +); + +CREATE TABLE IF NOT EXISTS opportunity_requirements ( + id SERIAL PRIMARY KEY, + opportunity_id INTEGER REFERENCES opportunities(id) ON DELETE CASCADE, + requirement_text TEXT NOT NULL, + requirement_type TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +\echo 'Opportunity tables created successfully.' + +-- ============================================================================ +-- SECTION 4: MATCHING AND ANALYTICS TABLES +-- ============================================================================ +-- Source: models/matches.sql + +\echo 'Creating matching and analytics tables...' + +CREATE TABLE IF NOT EXISTS match_results ( + id SERIAL PRIMARY KEY, + user_id TEXT REFERENCES user_profiles(username), + opportunity_id INTEGER REFERENCES opportunities(id), + + -- Scoring + semantic_similarity FLOAT, + eligibility_score FLOAT, + composite_score FLOAT, + + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + + UNIQUE(user_id, opportunity_id) +); + +CREATE TABLE IF NOT EXISTS match_criteria ( + id SERIAL PRIMARY KEY, + match_result_id INTEGER REFERENCES match_results(id) ON DELETE CASCADE, + criterion_type TEXT, + criterion_name TEXT, + is_met BOOLEAN, + notes TEXT +); + +CREATE TABLE IF NOT EXISTS search_queries ( + id SERIAL PRIMARY KEY, + user_id TEXT, + query_text TEXT, + query_embedding vector(384), + result_count INTEGER, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS search_filters ( + id SERIAL PRIMARY KEY, + search_query_id INTEGER REFERENCES search_queries(id) ON DELETE CASCADE, + filter_type TEXT, + filter_value TEXT +); + +CREATE TABLE IF NOT EXISTS user_applications ( + id SERIAL PRIMARY KEY, + user_id TEXT REFERENCES user_profiles(username), + opportunity_id INTEGER REFERENCES opportunities(id), + status TEXT, + applied_at TIMESTAMP, + notes TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Trigger to auto-update updated_at timestamp +CREATE TRIGGER update_user_applications_updated_at + BEFORE UPDATE ON user_applications + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +\echo 'Matching and analytics tables created successfully.' + +-- ============================================================================ +-- SECTION 5: PERFORMANCE INDEXES +-- ============================================================================ +-- Source: models/indicies.sql + +\echo 'Creating performance indexes...' + +-- Geographic indexes +CREATE INDEX IF NOT EXISTS idx_cities_country ON cities(country_id); +CREATE INDEX IF NOT EXISTS idx_cities_state ON cities(state_province_id); + +CREATE INDEX IF NOT EXISTS idx_addresses_country ON addresses(country_id); +CREATE INDEX IF NOT EXISTS idx_addresses_state ON addresses(state_province_id); +CREATE INDEX IF NOT EXISTS idx_addresses_city ON addresses(city_id); +CREATE INDEX IF NOT EXISTS idx_addresses_postal ON addresses(postal_code); +CREATE INDEX IF NOT EXISTS idx_addresses_coords ON addresses(latitude, longitude); + +-- Opportunity indexes +CREATE INDEX IF NOT EXISTS idx_opportunities_type ON opportunities(type); +CREATE INDEX IF NOT EXISTS idx_opportunities_deadline ON opportunities(deadline) WHERE is_active = TRUE; +CREATE INDEX IF NOT EXISTS idx_opportunities_active ON opportunities(is_active); +CREATE INDEX IF NOT EXISTS idx_opportunities_org ON opportunities(organization_id); +CREATE INDEX IF NOT EXISTS idx_document_chunks_opportunity ON opportunity_document_chunks(opportunity_id); + +-- Opportunity relationship indexes +CREATE INDEX IF NOT EXISTS idx_opportunity_majors_opp ON opportunity_majors(opportunity_id); +CREATE INDEX IF NOT EXISTS idx_opportunity_majors_major ON opportunity_majors(major_id); +CREATE INDEX IF NOT EXISTS idx_opportunity_citizenship_opp ON opportunity_citizenship(opportunity_id); +CREATE INDEX IF NOT EXISTS idx_opportunity_grade_levels_opp ON opportunity_grade_levels(opportunity_id); +CREATE INDEX IF NOT EXISTS idx_opportunity_skills_opp ON opportunity_skills(opportunity_id); +CREATE INDEX IF NOT EXISTS idx_opportunity_interests_opp ON opportunity_interests(opportunity_id); + +-- User relationship indexes +CREATE INDEX IF NOT EXISTS idx_user_skills_user ON user_skills(user_id); +CREATE INDEX IF NOT EXISTS idx_user_skills_skill ON user_skills(skill_id); +CREATE INDEX IF NOT EXISTS idx_user_interests_user ON user_interests(user_id); + +-- Matching and analytics indexes +CREATE INDEX IF NOT EXISTS idx_match_results_user ON match_results(user_id); +CREATE INDEX IF NOT EXISTS idx_match_results_opp ON match_results(opportunity_id); +CREATE INDEX IF NOT EXISTS idx_match_criteria_match ON match_criteria(match_result_id); + +CREATE INDEX IF NOT EXISTS idx_user_applications_user ON user_applications(user_id); +CREATE INDEX IF NOT EXISTS idx_user_applications_status ON user_applications(status); + +-- Vector similarity search indexes (HNSW for performance) +-- These indexes enable fast approximate nearest neighbor search for embeddings +CREATE INDEX IF NOT EXISTS idx_chunks_embedding ON opportunity_document_chunks +USING hnsw (embedding vector_cosine_ops) +WITH (m = 16, ef_construction = 64); + +CREATE INDEX IF NOT EXISTS idx_user_resume_embedding ON user_profiles +USING hnsw (resume_embedding vector_cosine_ops) +WITH (m = 16, ef_construction = 64); + +CREATE INDEX IF NOT EXISTS idx_search_queries_embedding ON search_queries +USING hnsw (query_embedding vector_cosine_ops) +WITH (m = 16, ef_construction = 64); + +-- Trigram indexes for fuzzy text search (using pg_trgm extension) +CREATE INDEX IF NOT EXISTS idx_opportunities_title_trgm ON opportunities +USING gin (title gin_trgm_ops); + +CREATE INDEX IF NOT EXISTS idx_opportunities_description_trgm ON opportunities +USING gin (description gin_trgm_ops); + +CREATE INDEX IF NOT EXISTS idx_organizations_name_trgm ON organizations +USING gin (name gin_trgm_ops); + +CREATE INDEX IF NOT EXISTS idx_majors_name_trgm ON majors +USING gin (name gin_trgm_ops); + +CREATE INDEX IF NOT EXISTS idx_skills_name_trgm ON skills +USING gin (name gin_trgm_ops); + +\echo 'Performance indexes created successfully.' + +-- ============================================================================ +-- SECTION 6: VIEWS AND HELPER QUERIES +-- ============================================================================ + +\echo 'Creating views...' + +-- Materialized view for opportunity statistics (can be refreshed periodically) +CREATE MATERIALIZED VIEW IF NOT EXISTS opportunity_stats AS +SELECT + type, + COUNT(*) as total_count, + AVG(min_gpa) as avg_min_gpa, + AVG(award_amount) as avg_award_amount, + AVG(salary_min) as avg_salary_min, + COUNT(*) FILTER (WHERE is_active = TRUE) as active_count, + COUNT(*) FILTER (WHERE deadline > CURRENT_TIMESTAMP) as upcoming_count +FROM opportunities +GROUP BY type; + +-- Create index on the materialized view +CREATE INDEX IF NOT EXISTS idx_opportunity_stats_type ON opportunity_stats(type); + +-- View for user profile summary with aggregated data +CREATE OR REPLACE VIEW user_profile_summary AS +SELECT + up.id, + up.username, + up.email, + up.gpa, + m.name as major_name, + gl.name as grade_level, + ct.name as citizenship, + COUNT(DISTINCT us.skill_id) as skill_count, + COUNT(DISTINCT ui.interest_id) as interest_count, + COUNT(DISTINCT ua.id) as application_count, + up.created_at +FROM user_profiles up +LEFT JOIN majors m ON up.major_id = m.id +LEFT JOIN grade_levels gl ON up.grade_level_id = gl.id +LEFT JOIN citizenship_types ct ON up.citizenship_id = ct.id +LEFT JOIN user_skills us ON up.username = us.user_id +LEFT JOIN user_interests ui ON up.username = ui.user_id +LEFT JOIN user_applications ua ON up.username = ua.user_id +GROUP BY up.id, up.username, up.email, up.gpa, m.name, gl.name, ct.name, up.created_at; + +\echo 'Views created successfully.' + +-- ============================================================================ +-- SECTION 7: DATABASE STATISTICS AND CLEANUP +-- ============================================================================ + +\echo 'Analyzing database...' + +-- Update table statistics for query planner +ANALYZE; + +-- Refresh materialized views +REFRESH MATERIALIZED VIEW opportunity_stats; \ No newline at end of file diff --git a/db/init.sql b/db/init.sql index ba2621b..24070ac 100644 --- a/db/init.sql +++ b/db/init.sql @@ -1,12 +1,93 @@ --- Initial database schema --- This will be replaced with proper migrations later +-- ============================================================================ +-- PostgreSQL Initialization Script +-- ============================================================================ +-- This script initializes the database with required extensions and settings +-- Extensions are installed at the database level before schema creation + +-- Enable required PostgreSQL extensions +-- These must be installed before any tables that use them are created + +-- pgvector: Vector similarity search for embeddings (ML/AI features) +-- Provides vector data type and similarity search operators +CREATE EXTENSION IF NOT EXISTS vector; + +-- pg_stat_statements: Track planning and execution statistics of all SQL statements +-- Essential for query performance monitoring and optimization +CREATE EXTENSION IF NOT EXISTS pg_stat_statements; + +-- pg_trgm: Trigram text similarity and indexing +-- Enables fuzzy text search and similarity matching (e.g., for searching opportunities) +CREATE EXTENSION IF NOT EXISTS pg_trgm; + +-- ============================================================================ +-- Database Configuration +-- ============================================================================ + +-- Optimize for vector similarity search workloads +-- Increase work_mem for better performance on vector operations +ALTER SYSTEM SET work_mem = '256MB'; + +-- Enable parallel query execution for better performance on large datasets +ALTER SYSTEM SET max_parallel_workers_per_gather = 4; +ALTER SYSTEM SET max_parallel_workers = 8; + +-- Optimize for HNSW index performance (used by pgvector) +ALTER SYSTEM SET maintenance_work_mem = '512MB'; + +-- Enable JIT compilation for complex queries +ALTER SYSTEM SET jit = 'on'; + +-- Configure pg_stat_statements +ALTER SYSTEM SET pg_stat_statements.track = 'all'; +ALTER SYSTEM SET pg_stat_statements.max = 10000; + +-- ============================================================================ +-- Health Check Table +-- ============================================================================ +-- Ensures database is accessible and responding --- Health check table (ensures DB is accessible) CREATE TABLE IF NOT EXISTS health_check ( id INTEGER PRIMARY KEY, - timestamp DATETIME DEFAULT CURRENT_TIMESTAMP + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + version TEXT DEFAULT '1.0.0', + status TEXT DEFAULT 'healthy' ); --- Insert initial health check -INSERT INTO health_check (id) VALUES (1) -ON CONFLICT(id) DO UPDATE SET timestamp = CURRENT_TIMESTAMP; +-- Insert initial health check record +INSERT INTO health_check (id, timestamp, version, status) +VALUES (1, CURRENT_TIMESTAMP, '1.0.0', 'healthy') +ON CONFLICT(id) DO UPDATE +SET timestamp = CURRENT_TIMESTAMP, + status = 'healthy'; + +-- ============================================================================ +-- Utility Functions +-- ============================================================================ + +-- Function to update the updated_at timestamp automatically +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Function to calculate cosine similarity between vectors (helper for queries) +CREATE OR REPLACE FUNCTION cosine_similarity(a vector, b vector) +RETURNS float AS $$ +BEGIN + RETURN 1 - (a <=> b); +END; +$$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; + +-- ============================================================================ +-- Initialization Complete +-- ============================================================================ +-- Extensions enabled: +-- โœ“ vector (pgvector) +-- โœ“ pg_stat_statements +-- โœ“ pg_trgm +-- +-- Next: Schema will be loaded from fiapply.sql +-- ============================================================================ diff --git a/db/models/indicies.sql b/db/models/indicies.sql index 187d375..714e314 100644 --- a/db/models/indicies.sql +++ b/db/models/indicies.sql @@ -18,7 +18,7 @@ CREATE INDEX IF NOT EXISTS idx_opportunities_type ON opportunities(type); CREATE INDEX IF NOT EXISTS idx_opportunities_deadline ON opportunities(deadline) WHERE is_active = TRUE; CREATE INDEX IF NOT EXISTS idx_opportunities_active ON opportunities(is_active); CREATE INDEX IF NOT EXISTS idx_opportunities_org ON opportunities(organization_id); -CREATE INDEX IF NOT EXISTS idx_document_chunks_opportunity ON document_chunks(opportunity_id); +CREATE INDEX IF NOT EXISTS idx_document_chunks_opportunity ON opportunity_document_chunks(opportunity_id); -- Foreign key indexes for join performance CREATE INDEX IF NOT EXISTS idx_opportunity_majors_opp ON opportunity_majors(opportunity_id); @@ -44,8 +44,8 @@ CREATE INDEX IF NOT EXISTS idx_chunks_embedding ON opportunity_document_chunks USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64); -CREATE INDEX IF NOT EXISTS idx_user_resume_embedding ON user_profiles -USING hnsw (resume_embedding vector_cosine_ops) +CREATE INDEX IF NOT EXISTS idx_user_document_embedding ON user_documents +USING hnsw (document_embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64); -- m = # of connections per layer, higher = better recall but more memory -- ef_construction = search scope during index building. higher = better quality but slower queries diff --git a/db/models/notes.txt b/db/models/notes.txt deleted file mode 100644 index f71a3a3..0000000 --- a/db/models/notes.txt +++ /dev/null @@ -1 +0,0 @@ -references -> opportunities -> users -> matches -> indicies \ No newline at end of file diff --git a/db/models/opportunities.sql b/db/models/opportunities.sql index b484952..7ff77d6 100644 --- a/db/models/opportunities.sql +++ b/db/models/opportunities.sql @@ -1,8 +1,7 @@ ------------ -- opportunities section ------------ - -CREATE EXTENSION vector; +CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE IF NOT EXISTS opportunities ( id SERIAL PRIMARY KEY, diff --git a/db/fi.db b/db/models/populate.sql similarity index 100% rename from db/fi.db rename to db/models/populate.sql diff --git a/db/models/users.sql b/db/models/users.sql index b85a07b..1015afa 100644 --- a/db/models/users.sql +++ b/db/models/users.sql @@ -1,11 +1,10 @@ ------------ -- user section ------------ - -CREATE EXTENSION vector; +CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE IF NOT EXISTS user_profiles ( - id INTEGER PRIMARY KEY, + id SERIAL PRIMARY KEY, username TEXT UNIQUE NOT NULL, email TEXT NOT NULL UNIQUE, @@ -20,12 +19,6 @@ CREATE TABLE IF NOT EXISTS user_profiles ( citizenship_id INTEGER REFERENCES citizenship_types(id), location TEXT, - --Resume and background - resume_text TEXT, - resume_embedding vector(384), - career_goals TEXT, - career_goals_embedding vector(384), --can leave null ? - --Preferences min_award_amount DECIMAL(10,2), min_salary_amount DECIMAL(10,2), @@ -34,9 +27,17 @@ CREATE TABLE IF NOT EXISTS user_profiles ( updated_at TIMESTAMP DEFAULT NOW() ); +CREATE TABLE IF NOT EXISTS user_documents ( + user_id INTEGER REFERENCES user_profiles(id) ON DELETE CASCADE, + document_id SERIAL PRIMARY KEY, + document_type TEXT CHECK (document_type IN ('resume', 'transcript', 'essay', 'career goals')), + document_text TEXT, + document_embedding vector(384) +); + --skills table CREATE TABLE IF NOT EXISTS user_skills ( - user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + user_id INTEGER REFERENCES user_profiles(id) ON DELETE CASCADE, skill_id INTEGER REFERENCES skills(id) ON DELETE CASCADE, proficiency_level TEXT, -- beginner, novice, intermediate, advanced, or expert. we could also do a like % or just a raw number years_experience DECIMAL(3,1), @@ -45,7 +46,7 @@ CREATE TABLE IF NOT EXISTS user_skills ( --interests table CREATE TABLE IF NOT EXISTS user_interests ( - user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + user_id INTEGER REFERENCES user_profiles(id) ON DELETE CASCADE, interest_id INTEGER REFERENCES interests(id) ON DELETE CASCADE, PRIMARY KEY(user_id, interest_id) ); @@ -53,7 +54,7 @@ CREATE TABLE IF NOT EXISTS user_interests ( --preferred opportunity types table CREATE TABLE IF NOT EXISTS user_preferred_types ( - user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + user_id INTEGER REFERENCES user_profiles(id) ON DELETE CASCADE, opportunity_type TEXT CHECK (opportunity_type IN ('scholarship', 'internship', 'job')), PRIMARY KEY(user_id, opportunity_type) ); @@ -63,7 +64,7 @@ CREATE TABLE IF NOT EXISTS user_preferred_types ( -- should we make a locations table ? CREATE TABLE IF NOT EXISTS user_preferred_locations ( id SERIAL PRIMARY KEY, - user_id TEXT REFERENCES user_profiles(username) ON DELETE CASCADE, + user_id INTEGER REFERENCES user_profiles(id) ON DELETE CASCADE, location TEXT NOT NULL, is_flexible BOOLEAN DEFAULT FALSE ); diff --git a/db/notes.txt b/db/notes.txt new file mode 100644 index 0000000..b15956d --- /dev/null +++ b/db/notes.txt @@ -0,0 +1,5 @@ +to create db models properly, init in the following order + +references -> opportunities -> users -> matches -> indicies + +teardown i think can happen in any order? \ No newline at end of file diff --git a/db/retrieval/rag.sql b/db/retrieval/rag.sql index f9de439..a5bb8a5 100644 --- a/db/retrieval/rag.sql +++ b/db/retrieval/rag.sql @@ -32,8 +32,6 @@ -- -- storedocument (hard) -- -- retrievecontext -CREATE EXTENSION vector; - /* two stage retrieval sql filter, diff --git a/db/schema.sql b/db/schema.sql deleted file mode 100644 index c6725b8..0000000 --- a/db/schema.sql +++ /dev/null @@ -1 +0,0 @@ --- DB Schema here \ No newline at end of file diff --git a/db/teardown.sql b/db/teardown.sql new file mode 100644 index 0000000..baa622b --- /dev/null +++ b/db/teardown.sql @@ -0,0 +1,37 @@ +-- Drop tables in reverse dependency order (children first, parents last) +-- Use CASCADE to automatically drop dependent objects + +DROP TABLE IF EXISTS user_applications CASCADE; +DROP TABLE IF EXISTS user_skills CASCADE; +DROP TABLE IF EXISTS user_interests CASCADE; +DROP TABLE IF EXISTS user_preferred_locations CASCADE; +DROP TABLE IF EXISTS user_preferred_types CASCADE; +DROP TABLE IF EXISTS user_documents CASCADE; +DROP TABLE IF EXISTS user_profiles CASCADE; + +DROP TABLE IF EXISTS match_results CASCADE; +DROP TABLE IF EXISTS match_criteria CASCADE; +DROP TABLE IF EXISTS search_queries CASCADE; +DROP TABLE IF EXISTS search_filters CASCADE; + +DROP TABLE IF EXISTS opportunity_document_chunks CASCADE; +DROP TABLE IF EXISTS opportunity_citizenship CASCADE; +DROP TABLE IF EXISTS opportunity_grade_levels CASCADE; +DROP TABLE IF EXISTS opportunity_interests CASCADE; +DROP TABLE IF EXISTS opportunity_majors CASCADE; +DROP TABLE IF EXISTS opportunity_requirements CASCADE; +DROP TABLE IF EXISTS opportunity_skills CASCADE; +DROP TABLE IF EXISTS opportunities CASCADE; + +DROP TABLE IF EXISTS organizations CASCADE; + +DROP TABLE IF EXISTS addresses CASCADE; +DROP TABLE IF EXISTS cities CASCADE; +DROP TABLE IF EXISTS states_provinces CASCADE; +DROP TABLE IF EXISTS countries CASCADE; + +DROP TABLE IF EXISTS citizenship_types CASCADE; +DROP TABLE IF EXISTS grade_levels CASCADE; +DROP TABLE IF EXISTS interests CASCADE; +DROP TABLE IF EXISTS majors CASCADE; +DROP TABLE IF EXISTS skills CASCADE; \ No newline at end of file diff --git a/db/test/user_dummy.sql b/db/test/user_dummy.sql new file mode 100644 index 0000000..441c766 --- /dev/null +++ b/db/test/user_dummy.sql @@ -0,0 +1,7 @@ +-- Sample User Profiles +INSERT INTO user_profiles (username, email, gpa, major_id, grade_level_id, graduate_date, university, citizenship_id, location, min_award_amount, min_salary_amount) VALUES +('alice_chen', 'alice.chen@email.com', 3.85, NULL, NULL, '2026-05-15', 'Stanford University', NULL, 'Palo Alto, CA', 5000.00, 65000.00), +('bob_martinez', 'bob.martinez@email.com', 3.42, NULL, NULL, '2025-12-20', 'University of Texas at Austin', NULL, 'Austin, TX', 2500.00, 55000.00), +('carol_nguyen', 'carol.nguyen@email.com', 3.91, NULL, NULL, '2027-05-30', 'MIT', NULL, 'Cambridge, MA', 10000.00, 85000.00), +('david_smith', 'david.smith@email.com', 3.28, NULL, NULL, '2025-05-15', 'Ohio State University', NULL, 'Columbus, OH', 3000.00, 50000.00), +('emma_patel', 'emma.patel@email.com', 3.67, NULL, NULL, '2026-12-15', 'UC Berkeley', NULL, 'Berkeley, CA', 7500.00, 70000.00); \ No newline at end of file diff --git a/docker-compose.minimal.yml b/docker-compose.minimal.yml index 719c212..c25aaad 100644 --- a/docker-compose.minimal.yml +++ b/docker-compose.minimal.yml @@ -1,8 +1,3 @@ -version: '3.9' - -# Minimal setup - just essential services -# Usage: docker-compose -f docker-compose.minimal.yml up - services: # API Gateway api-gateway: diff --git a/docker-compose.yml b/docker-compose.yml index e34d61d..63e64af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.9' - services: # API Gateway - Client entry point api-gateway: @@ -88,13 +86,20 @@ services: environment: # Docker-specific overrides - RAG_ENGINE_PORT=50053 - - DB_PATH=/app/db/fi.db + - DB_HOST=postgres + - DB_PORT=5432 + - DB_NAME=fiapply + - DB_USER=fiapply_user + - DB_PASSWORD=fiapply_password - EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 - LOG_LEVEL=INFO volumes: - ./backend:/app/backend - ./db:/app/db - rag-data:/app/.cache + depends_on: + postgres: + condition: service_healthy networks: - fi-network @@ -119,12 +124,10 @@ services: - LOG_LEVEL=INFO volumes: - ./backend:/app/backend - depends_on: - - ollama networks: - fi-network - # Frontend - React TypeScript app + # Frontend - Electron + React TypeScript app frontend: build: context: ./frontend @@ -132,17 +135,19 @@ services: target: development container_name: fi-frontend ports: - - "3000:3000" + - "5173:5173" # Electron-vite dev server port env_file: - .env # Root-level shared config - frontend/.env # Service-specific config (optional) environment: # Docker-specific overrides - VITE_API_BASE_URL=http://localhost:50051 + - VITE_GRPC_BASE_URL=http://localhost:9090 - VITE_ENV=development volumes: - ./frontend:/app - /app/node_modules + - /app/out depends_on: - api-gateway networks: @@ -200,22 +205,50 @@ services: networks: - fi-network - # SQLite Web - Database browser (optional, lightweight) - sqlite-web: - image: coleifer/sqlite-web:latest - container_name: fi-sqlite-web + # PostgreSQL Database - Primary data store + postgres: + build: + context: ./db + dockerfile: Dockerfile + container_name: fi-postgres ports: - - "8082:8080" + - "5432:5432" + environment: + - POSTGRES_DB=fiapply + - POSTGRES_USER=fiapply_user + - POSTGRES_PASSWORD=fiapply_password + - PGDATA=/var/lib/postgresql/data/pgdata volumes: - - ./db:/data - command: ["/data/fi.db"] + - postgres-data:/var/lib/postgresql/data + - ./db/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro + - ./db/fiapply.sql:/docker-entrypoint-initdb.d/02-schema.sql:ro networks: - fi-network healthcheck: - test: ["CMD", "test", "-f", "/data/fi.db"] - interval: 30s + test: ["CMD-SHELL", "pg_isready -U fiapply_user -d fiapply"] + interval: 10s timeout: 5s - retries: 3 + retries: 5 + start_period: 30s + + # pgAdmin - PostgreSQL web interface (optional) + pgadmin: + image: dpage/pgadmin4:latest + container_name: fi-pgadmin + ports: + - "5050:80" + environment: + - PGADMIN_DEFAULT_EMAIL=admin@fiapply.local + - PGADMIN_DEFAULT_PASSWORD=admin + - PGADMIN_CONFIG_SERVER_MODE=False + volumes: + - pgadmin-data:/var/lib/pgadmin + depends_on: + - postgres + networks: + - fi-network + profiles: + - tools # Only start with --profile tools networks: fi-network: @@ -226,3 +259,7 @@ volumes: driver: local rag-data: driver: local + postgres-data: + driver: local + pgadmin-data: + driver: local diff --git a/docs/context/Architecture.md b/docs/context/Architecture.md index 9c91c2d..13c954a 100644 --- a/docs/context/Architecture.md +++ b/docs/context/Architecture.md @@ -21,7 +21,7 @@ end subgraph Local["**Local Environment**"] APIServer["**API Gateway**
*Python*"] AIService - SQLite[("**Local DB**
*SQLite*")] + Postgres[("**Database**
*PostgreSQL*")] Ollama["**Ollama**
*CLI LLM Runtime*"] end @@ -32,8 +32,8 @@ end User <-- HTTP --> React React <-- gRPC/JSON --> APIServer APIServer <-- gRPC --> AIServer -APIServer <-- TCP --> SQLite -RAGEngine <-- TCP --> SQLite +APIServer <-- TCP --> Postgres +RAGEngine <-- TCP --> Postgres AIServer <-- gRPC --> RAGEngine & OllamaClient OllamaClient <-- HTTP --> Ollama OllamaClient <-. HTTPS .-> OpenRouter @@ -59,12 +59,12 @@ OllamaClient <-. HTTPS .-> OpenRouter - Handles request validation and error handling - Manages authentication and authorization for MVP -**Local DB** (*SQLite*) +**Database** (*PostgreSQL*) - Stores user data, application state, and documents -- Provides vector search capabilities for RAG operations +- Provides vector search capabilities via pgvector for RAG operations - Persists conversation history and user preferences -- Local-first data storage for privacy +- Full-featured relational database with advanced indexing **Ollama** (*CLI LLM Runtime*) @@ -119,7 +119,7 @@ OllamaClient <-. HTTPS .-> OpenRouter **AI Processing Flow:** -1. RAG Engine retrieves relevant context from SQLite +1. RAG Engine retrieves relevant context from PostgreSQL 2. AI Orchestrator builds prompt with context 3. LLM Manager sends to either Ollama (local) or OpenRouter (cloud) 4. Response processed and returned to user diff --git a/docs/context/Tech Stack.md b/docs/context/Tech Stack.md index 19dfb8d..a48e26c 100644 --- a/docs/context/Tech Stack.md +++ b/docs/context/Tech Stack.md @@ -17,8 +17,10 @@ ## Database -- SQLite -- Vector plugins for RAG operations +- PostgreSQL 18 Alpine +- pgvector for vector similarity search +- pg_trgm for fuzzy text search +- pg_stat_statements for query monitoring ## Misc diff --git a/docs/openapi/fi-api.swagger.json b/docs/openapi/fi-api.swagger.json index c4b34a5..8bfd526 100644 --- a/docs/openapi/fi-api.swagger.json +++ b/docs/openapi/fi-api.swagger.json @@ -19,6 +19,9 @@ }, { "name": "RAGEngine" + }, + { + "name": "VectorDBService" } ], "consumes": [ @@ -627,6 +630,72 @@ "RAGEngine" ] } + }, + "/fi.rag.v1.VectorDBService/EmbedScholarshipBatch": { + "post": { + "summary": "Embed a batch of scholarships and store them", + "operationId": "VectorDBService_EmbedScholarshipBatch", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/EmbedScholarshipBatchResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpc.Status" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/EmbedScholarshipBatchRequest" + } + } + ], + "tags": [ + "VectorDBService" + ] + } + }, + "/fi.rag.v1.VectorDBService/Init": { + "post": { + "summary": "Initialize vector DB connection or collection", + "operationId": "VectorDBService_Init", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/InitResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpc.Status" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/InitRequest" + } + } + ], + "tags": [ + "VectorDBService" + ] + } } }, "definitions": { @@ -800,6 +869,31 @@ } } }, + "EmbedScholarshipBatchRequest": { + "type": "object", + "properties": { + "scholarships": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/Scholarship" + }, + "title": "Example dataclass converted below" + } + } + }, + "EmbedScholarshipBatchResponse": { + "type": "object", + "properties": { + "totalEmbedded": { + "type": "integer", + "format": "int32" + }, + "error": { + "$ref": "#/definitions/Error" + } + } + }, "EmbeddingRequest": { "type": "object", "properties": { @@ -1020,6 +1114,29 @@ } } }, + "InitRequest": { + "type": "object", + "properties": { + "connectionString": { + "type": "string", + "title": "e.g. \"postgresql://user:pass@localhost/db\"" + }, + "collectionName": { + "type": "string" + } + } + }, + "InitResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "error": { + "$ref": "#/definitions/Error" + } + } + }, "KeyDownPayload": { "type": "object", "properties": { @@ -1265,6 +1382,55 @@ } } }, + "Scholarship": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32", + "title": "Unique scholarship identifier" + }, + "name": { + "type": "string", + "title": "Scholarship name" + }, + "description": { + "type": "string", + "title": "Scholarship description or summary" + }, + "minGpa": { + "type": "number", + "format": "double", + "title": "Minimum GPA required (e.g. 3.5)" + }, + "eligibleMajors": { + "type": "array", + "items": { + "type": "string" + }, + "title": "Eligible majors (e.g. \"Computer Science\", \"Engineering\")" + }, + "citizenshipRequired": { + "type": "string", + "title": "Citizenship requirement (optional, can be null)" + }, + "location": { + "type": "string", + "title": "Location requirement or region (optional)" + }, + "awardAmount": { + "type": "string", + "title": "Award amount or range, kept as a string for flexibility" + }, + "keywords": { + "type": "array", + "items": { + "type": "string" + }, + "title": "Keywords for semantic search / classification" + } + } + }, "Screenshot": { "type": "object", "properties": { diff --git a/docs/usage/environment-vars.md b/docs/usage/environment-vars.md index f449441..22f6ab7 100644 --- a/docs/usage/environment-vars.md +++ b/docs/usage/environment-vars.md @@ -106,9 +106,14 @@ LOG_LEVEL=INFO # ============================================================================= # DATABASE CONFIGURATION (Shared) # ============================================================================= -DATABASE_PATH=./db/fi.db -DATABASE_URL=sqlite:///./db/fi.db -DB_PATH=./db/fi.db +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=fiapply +DB_USER=fiapply_user +DB_PASSWORD=fiapply_password + +# Connection string format +DATABASE_URL=postgresql://fiapply_user:fiapply_password@localhost:5432/fiapply # ============================================================================= # EXTERNAL API KEYS (Shared across services) @@ -264,7 +269,11 @@ RAG_ENGINE_PORT=50053 # ============================================================================= # DATABASE SETTINGS # ============================================================================= -DB_PATH=./db/fi.db +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=fiapply +DB_USER=fiapply_user +DB_PASSWORD=fiapply_password # ============================================================================= # EMBEDDING SETTINGS diff --git a/electron/.gitignore b/electron/.gitignore deleted file mode 100644 index 32752c7..0000000 --- a/electron/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -dist -out -*.local -**/.DS_Store -*.tsbuildinfo -.vite diff --git a/electron/README.md b/electron/README.md deleted file mode 100644 index c1b382b..0000000 --- a/electron/README.md +++ /dev/null @@ -1,404 +0,0 @@ -# FiApply Electron Application - -Electron desktop application built with Vite, React, and TypeScript. - -## Project Structure - -``` -electron/ -โ”œโ”€โ”€ src/ -โ”‚ โ”œโ”€โ”€ main/ # Electron main process (Node.js) -โ”‚ โ”‚ โ””โ”€โ”€ index.ts -โ”‚ โ”œโ”€โ”€ preload/ # Preload scripts (bridge between main/renderer) -โ”‚ โ”‚ โ”œโ”€โ”€ index.ts -โ”‚ โ”‚ โ””โ”€โ”€ index.d.ts -โ”‚ โ”œโ”€โ”€ renderer/ # Frontend React application -โ”‚ โ”‚ โ”œโ”€โ”€ index.html -โ”‚ โ”‚ โ””โ”€โ”€ src/ -โ”‚ โ”‚ โ”œโ”€โ”€ main.tsx # React entry point -โ”‚ โ”‚ โ”œโ”€โ”€ App.tsx # Main React component -โ”‚ โ”‚ โ”œโ”€โ”€ style.css -โ”‚ โ”‚ โ””โ”€โ”€ hooks/ # Custom React hooks -โ”‚ โ”‚ โ”œโ”€โ”€ data/ # Data fetching hooks (useRPC, useUpdateSignal) -โ”‚ โ”‚ โ”œโ”€โ”€ state/ # State management hooks -โ”‚ โ”‚ โ”œโ”€โ”€ ui/ # UI-related hooks -โ”‚ โ”‚ โ””โ”€โ”€ utils/ # Utility hooks (useDebounce, etc.) -โ”‚ โ”œโ”€โ”€ services/ # Service classes (shared logic) -โ”‚ โ”‚ โ”œโ”€โ”€ LoggerService.ts -โ”‚ โ”‚ โ”œโ”€โ”€ RPCService.ts -โ”‚ โ”‚ โ””โ”€โ”€ UpdateSignalManager.ts -โ”‚ โ”œโ”€โ”€ store/ # Redux/state management -โ”‚ โ”‚ โ”œโ”€โ”€ index.ts -โ”‚ โ”‚ โ””โ”€โ”€ hooks.ts -โ”‚ โ”œโ”€โ”€ types/ # TypeScript type definitions -โ”‚ โ”‚ โ”œโ”€โ”€ global/ # Global types available everywhere -โ”‚ โ”‚ โ”œโ”€โ”€ node/ # Types for main/preload processes -โ”‚ โ”‚ โ””โ”€โ”€ renderer/ # Types for renderer process -โ”‚ โ””โ”€โ”€ generated/ # Auto-generated Protobuf files -โ”‚ โ””โ”€โ”€ *_pb.ts -โ”œโ”€โ”€ electron.vite.config.ts # Vite configuration for all processes -โ”œโ”€โ”€ tsconfig.json # Root TypeScript config (for build tools) -โ”œโ”€โ”€ tsconfig.node.json # TypeScript config for main/preload -โ”œโ”€โ”€ tsconfig.renderer.json # TypeScript config for renderer -โ””โ”€โ”€ package.json -``` - -## Quick Start - -### Install Dependencies - -```bash -npm install -``` - -### Development - -Start development server with hot reload: - -```bash -npm run dev -``` - -This will: -- Start Vite dev server for the renderer (React) -- Watch and compile main/preload processes -- Launch Electron with DevTools -- Enable hot module replacement - -### Build - -Create production build: - -```bash -npm run build -``` - -Output will be in the `out/` directory: -- `out/main/` - Main process bundle -- `out/preload/` - Preload scripts bundle -- `out/renderer/` - Renderer (React) bundle - -### Preview Production Build - -Test the production build locally: - -```bash -npm run preview -# or -npm start -``` - -### Type Checking - -Check TypeScript types without building: - -```bash -npm run typecheck # Check all processes -npm run typecheck:node # Check main & preload only -npm run typecheck:web # Check renderer only -``` - -## NPM Scripts Reference - -| Command | Description | -|---------|-------------| -| `npm run dev` | Start development mode with hot reload | -| `npm run build` | Build for production | -| `npm run preview` | Run production build locally | -| `npm start` | Alias for `preview` | -| `npm run typecheck` | Type check all TypeScript files | -| `npm run typecheck:node` | Type check main & preload processes | -| `npm run typecheck:web` | Type check renderer process | - -## Tech Stack - -- **Electron** 28.0.0 - Desktop application framework -- **Vite** 5.4.11 - Build tool and dev server -- **React** 18.3.1 - UI library -- **TypeScript** 5.8.3 - Type-safe JavaScript -- **electron-vite** 2.3.0 - Vite integration for Electron - -## Development Notes - -### Process Architecture - -- **Main Process**: Controls app lifecycle, creates windows, manages system-level operations -- **Preload Scripts**: Secure bridge between main and renderer with context isolation -- **Renderer Process**: React frontend running in Chromium - -### Hot Module Replacement - -- **Renderer changes**: Instant HMR with state preservation -- **Main/Preload changes**: Automatic Electron restart - -### Path Aliases - -Renderer code can use `@renderer/*` alias: - -```typescript -import { Component } from '@renderer/components/Component' -``` - -### Accessing Electron APIs in Renderer - -Use the exposed APIs via preload: - -```typescript -// Access Electron APIs -window.electron.process.platform - -// Access custom APIs -window.api.yourCustomMethod() -``` - -## Common Tasks - -### Adding TypeScript Types - -Types are organized by their scope and usage: - -#### Global Types (Used Everywhere) -**Location**: `src/types/global/` - -Use for types shared across all processes (main, preload, renderer): -```typescript -// src/types/global/app.ts -export interface AppConfig { - name: string; - version: string; -} -``` - -Register in `tsconfig.node.json` and `tsconfig.renderer.json`: -```json -{ - "compilerOptions": { - "types": ["node", "src/types/global"] - } -} -``` - -#### Node/Main Process Types -**Location**: `src/types/node/` - -Use for types specific to main process and preload scripts: -```typescript -// src/types/node/ipc.ts -export interface IpcChannels { - 'file:open': string; - 'app:quit': void; -} -``` - -Referenced in `tsconfig.node.json`: -```json -{ - "compilerOptions": { - "types": ["node", "src/types/global", "src/types/node"] - } -} -``` - -#### Renderer Process Types -**Location**: `src/types/renderer/` - -Use for types specific to React/UI code: -```typescript -// src/types/renderer/components.ts -export interface ButtonProps { - variant: 'primary' | 'secondary'; - onClick: () => void; -} -``` - -### Adding React Hooks - -Custom hooks go in `src/renderer/src/hooks/`, organized by category: - -#### Data Hooks (`hooks/data/`) -For data fetching, API calls, and real-time updates: - -```typescript -// src/renderer/src/hooks/data/useUser.ts -import { useState, useEffect } from 'react'; - -export function useUser(userId: string) { - const [user, setUser] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - // Fetch user data - fetchUser(userId).then(setUser).finally(() => setLoading(false)); - }, [userId]); - - return { user, loading }; -} -``` - -**Examples**: `useRPC.ts`, `useUpdateSignal.ts` - -#### State Hooks (`hooks/state/`) -For Redux/Zustand integration or complex state management: - -```typescript -// src/renderer/src/hooks/state/useAppState.ts -import { useSelector, useDispatch } from 'react-redux'; - -export function useAppState() { - const state = useSelector((state) => state.app); - const dispatch = useDispatch(); - - return { state, dispatch }; -} -``` - -#### UI Hooks (`hooks/ui/`) -For UI behavior, animations, and browser APIs: - -```typescript -// src/renderer/src/hooks/ui/useWindowSize.ts -import { useState, useEffect } from 'react'; - -export function useWindowSize() { - const [size, setSize] = useState({ - width: window.innerWidth, - height: window.innerHeight - }); - - useEffect(() => { - const handleResize = () => setSize({ - width: window.innerWidth, - height: window.innerHeight - }); - - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - }, []); - - return size; -} -``` - -#### Utils Hooks (`hooks/utils/`) -For utility functions and helpers: - -```typescript -// src/renderer/src/hooks/utils/useDebounce.ts -import { useState, useEffect } from 'react'; - -export function useDebounce(value: T, delay: number): T { - const [debouncedValue, setDebouncedValue] = useState(value); - - useEffect(() => { - const handler = setTimeout(() => setDebouncedValue(value), delay); - return () => clearTimeout(handler); - }, [value, delay]); - - return debouncedValue; -} -``` - -**Examples**: `useDebounce.ts` - -#### Re-export Hooks -Create an `index.ts` in each category to re-export hooks: - -```typescript -// src/renderer/src/hooks/data/index.ts -export * from './useRPC'; -export * from './useUpdateSignal'; -export * from './useUser'; -``` - -Then import from the category: -```typescript -import { useRPC, useUpdateSignal } from '@renderer/hooks/data'; -``` - -### Adding React Components - -Create components in `src/renderer/src/`: - -```tsx -// src/renderer/src/components/MyComponent.tsx -interface MyComponentProps { - title: string -} - -function MyComponent({ title }: MyComponentProps) { - return

{title}

-} - -export default MyComponent -``` - -### Adding Dependencies - -```bash -# Runtime dependencies (e.g., React libraries) -npm install package-name - -# Development dependencies (e.g., types, build tools) -npm install -D package-name -``` - -### Configuring Vite - -Edit `electron.vite.config.ts` to customize: -- Vite plugins -- Path aliases -- Build options -- Dev server settings - -### TypeScript Configuration - -Three separate configs serve different purposes: - -- **`tsconfig.json`** - Config for build tools (electron.vite.config.ts) - - Extends `tsconfig.node.json` - - Adds `electron-vite/node` types for Vite API - - Only includes the Vite config file - -- **`tsconfig.node.json`** - Config for main & preload (Node.js environment) - - Targets ES2020 with Node.js types - - Includes `src/main/**/*` and main process code - - No DOM or JSX support - -- **`tsconfig.renderer.json`** - Config for renderer (browser environment) - - Includes DOM and React types - - Supports JSX with `react-jsx` transform - - Path aliases for `@renderer/*` imports - - Includes `src/renderer/**/*` and UI code - -Each config is necessary because the three contexts (build tools, Node.js, browser) require different: -- Type definitions (Node vs DOM APIs) -- Language features (JSX support) -- Module resolution strategies -- Compilation targets - -## Troubleshooting - -### Port Already in Use - -If dev server port is in use, electron-vite will automatically try another port. - -### Type Errors - -Run `npm run typecheck` to see detailed TypeScript errors. - -### Build Errors - -1. Clear build cache: `rm -rf out/` -2. Reinstall dependencies: `rm -rf node_modules && npm install` -3. Rebuild: `npm run build` - -### Hot Reload Not Working - -Restart the dev server with `npm run dev`. - -## Resources - -- [electron-vite Documentation](https://electron-vite.org/) -- [Electron Documentation](https://www.electronjs.org/docs/latest) -- [React Documentation](https://react.dev/) -- [Vite Documentation](https://vitejs.dev/) diff --git a/electron/package-lock.json b/electron/package-lock.json deleted file mode 100644 index 91026c0..0000000 --- a/electron/package-lock.json +++ /dev/null @@ -1,2578 +0,0 @@ -{ - "name": "fiapply-electron", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "fiapply-electron", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@bufbuild/protobuf": "^2.9.0", - "@connectrpc/connect-web": "^2.1.0", - "@electron-toolkit/preload": "^3.0.1", - "@electron-toolkit/utils": "^3.0.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "tslog": "^4.10.2" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "electron": "^28.0.0", - "electron-vite": "^2.3.0", - "typescript": "^5.8.3", - "vite": "^5.4.11" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.4" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bufbuild/protobuf": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.9.0.tgz", - "integrity": "sha512-rnJenoStJ8nvmt9Gzye8nkYd6V22xUAnu4086ER7h1zJ508vStko4pMvDeQ446ilDTFpV5wnoc5YS7XvMwwMqA==", - "license": "(Apache-2.0 AND BSD-3-Clause)" - }, - "node_modules/@connectrpc/connect": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.1.0.tgz", - "integrity": "sha512-xhiwnYlJNHzmFsRw+iSPIwXR/xweTvTw8x5HiwWp10sbVtd4OpOXbRgE7V58xs1EC17fzusF1f5uOAy24OkBuA==", - "license": "Apache-2.0", - "peer": true, - "peerDependencies": { - "@bufbuild/protobuf": "^2.7.0" - } - }, - "node_modules/@connectrpc/connect-web": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-2.1.0.tgz", - "integrity": "sha512-4IBFeMeXS1RVtmmFE/MwH+vWq/5vDRKys70va+DAaWDh83Rdy0iUQOJbITUDzvonlY5as3vwfs5yy9Yp2miHSw==", - "license": "Apache-2.0", - "peerDependencies": { - "@bufbuild/protobuf": "^2.7.0", - "@connectrpc/connect": "2.1.0" - } - }, - "node_modules/@electron-toolkit/preload": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@electron-toolkit/preload/-/preload-3.0.2.tgz", - "integrity": "sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==", - "license": "MIT", - "peerDependencies": { - "electron": ">=13.0.0" - } - }, - "node_modules/@electron-toolkit/utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@electron-toolkit/utils/-/utils-3.0.0.tgz", - "integrity": "sha512-GaXHDhiT7KCvMJjXdp/QqpYinq69T/Pdl49Z1XLf8mKGf63dnsODMWyrmIjEQ0z/vG7dO8qF3fvmI6Eb2lUNZA==", - "license": "MIT", - "peerDependencies": { - "electron": ">=13.0.0" - } - }, - "node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", - "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", - "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", - "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", - "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", - "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", - "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", - "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", - "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", - "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", - "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", - "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", - "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", - "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", - "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", - "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", - "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", - "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", - "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", - "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", - "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", - "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", - "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "license": "MIT" - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "22.18.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.8.tgz", - "integrity": "sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", - "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.13", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.13.tgz", - "integrity": "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "license": "MIT", - "optional": true - }, - "node_modules/browserslist": { - "version": "4.26.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", - "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "license": "MIT", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001748", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", - "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", - "optional": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "license": "MIT", - "optional": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "license": "MIT", - "optional": true - }, - "node_modules/electron": { - "version": "28.3.3", - "resolved": "https://registry.npmjs.org/electron/-/electron-28.3.3.tgz", - "integrity": "sha512-ObKMLSPNhomtCOBAxFS8P2DW/4umkh72ouZUlUKzXGtYuPzgr1SYhskhFWgzAsPtUzhL2CzyV2sfbHcEW4CXqw==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^18.11.18", - "extract-zip": "^2.0.1" - }, - "bin": { - "electron": "cli.js" - }, - "engines": { - "node": ">= 12.20.55" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.232", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.232.tgz", - "integrity": "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg==", - "dev": true, - "license": "ISC" - }, - "node_modules/electron-vite": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-2.3.0.tgz", - "integrity": "sha512-lsN2FymgJlp4k6MrcsphGqZQ9fKRdJKasoaiwIrAewN1tapYI/KINLdfEL7n10LuF0pPSNf/IqjzZbB5VINctg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.24.7", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "cac": "^6.7.14", - "esbuild": "^0.21.5", - "magic-string": "^0.30.10", - "picocolors": "^1.0.1" - }, - "bin": { - "electron-vite": "bin/electron-vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@swc/core": "^1.0.0", - "vite": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - } - } - }, - "node_modules/electron/node_modules/@types/node": { - "version": "18.19.129", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.129.tgz", - "integrity": "sha512-hrmi5jWt2w60ayox3iIXwpMEnfUvOLJCRtrOPbHtH15nTjvO7uhnelvrdAs0dO0/zl5DZ3ZbahiaXEVb54ca/A==", - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/electron/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "license": "MIT", - "optional": true - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "optional": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "license": "BSD-2-Clause" - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "license": "MIT" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "license": "ISC", - "optional": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "license": "MIT", - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", - "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "license": "MIT" - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "license": "MIT", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/rollup": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", - "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.4", - "@rollup/rollup-android-arm64": "4.52.4", - "@rollup/rollup-darwin-arm64": "4.52.4", - "@rollup/rollup-darwin-x64": "4.52.4", - "@rollup/rollup-freebsd-arm64": "4.52.4", - "@rollup/rollup-freebsd-x64": "4.52.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", - "@rollup/rollup-linux-arm-musleabihf": "4.52.4", - "@rollup/rollup-linux-arm64-gnu": "4.52.4", - "@rollup/rollup-linux-arm64-musl": "4.52.4", - "@rollup/rollup-linux-loong64-gnu": "4.52.4", - "@rollup/rollup-linux-ppc64-gnu": "4.52.4", - "@rollup/rollup-linux-riscv64-gnu": "4.52.4", - "@rollup/rollup-linux-riscv64-musl": "4.52.4", - "@rollup/rollup-linux-s390x-gnu": "4.52.4", - "@rollup/rollup-linux-x64-gnu": "4.52.4", - "@rollup/rollup-linux-x64-musl": "4.52.4", - "@rollup/rollup-openharmony-arm64": "4.52.4", - "@rollup/rollup-win32-arm64-msvc": "4.52.4", - "@rollup/rollup-win32-ia32-msvc": "4.52.4", - "@rollup/rollup-win32-x64-gnu": "4.52.4", - "@rollup/rollup-win32-x64-msvc": "4.52.4", - "fsevents": "~2.3.2" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "license": "MIT", - "optional": true - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "license": "MIT", - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/sumchecker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.1.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/tslog": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/tslog/-/tslog-4.10.2.tgz", - "integrity": "sha512-XuELoRpMR+sq8fuWwX7P0bcj+PRNiicOKDEb3fGNURhxWVyykCi9BNq7c4uVz7h7P0sj8qgBsr5SWS6yBClq3g==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/fullstack-build/tslog?sponsor=1" - } - }, - "node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "license": "(MIT OR CC0-1.0)", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/vite": { - "version": "5.4.20", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", - "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } -} diff --git a/electron/package.json b/electron/package.json deleted file mode 100644 index 375586d..0000000 --- a/electron/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "fiapply-electron", - "version": "1.0.0", - "description": "FiApply Desktop Application - Electron Vite", - "main": "./out/main/index.js", - "author": "Firelight Innovations", - "license": "ISC", - "scripts": { - "dev": "electron-vite dev", - "build": "electron-vite build", - "preview": "electron-vite preview", - "start": "electron-vite preview", - "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", - "typecheck:renderer": "tsc --noEmit -p tsconfig.renderer.json --composite false", - "typecheck": "npm run typecheck:node && npm run typecheck:renderer" - }, - "dependencies": { - "@bufbuild/protobuf": "^2.9.0", - "@connectrpc/connect-web": "^2.1.0", - "@electron-toolkit/preload": "^3.0.1", - "@electron-toolkit/utils": "^3.0.0", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "tslog": "^4.10.2" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "electron": "^28.0.0", - "electron-vite": "^2.3.0", - "typescript": "^5.8.3", - "vite": "^5.4.11" - } -} diff --git a/electron/src/generated/ai_orchestrator_connect.ts b/electron/src/generated/ai_orchestrator_connect.ts deleted file mode 100644 index 35e9d25..0000000 --- a/electron/src/generated/ai_orchestrator_connect.ts +++ /dev/null @@ -1,63 +0,0 @@ -// @generated by protoc-gen-connect-es v1.6.1 with parameter "target=ts" -// @generated from file ai_orchestrator.proto (package fi.ai.orchestrator.v1, syntax proto3) -/* eslint-disable */ -// @ts-nocheck - -import { EssayRequest, EssayResponse, ResumeRequest, ResumeResponse, TaskRequest, TaskResponse, TaskUpdate } from "./ai_orchestrator_pb.js"; -import { MethodKind } from "@bufbuild/protobuf"; - -/** - * AI Orchestrator - Coordinates AI operations and browser automation - * - * @generated from service fi.ai.orchestrator.v1.AIOrchestrator - */ -export const AIOrchestrator = { - typeName: "fi.ai.orchestrator.v1.AIOrchestrator", - methods: { - /** - * Execute a browser automation task (job application, form filling, etc.) - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.ExecuteTask - */ - executeTask: { - name: "ExecuteTask", - I: TaskRequest, - O: TaskResponse, - kind: MethodKind.Unary, - }, - /** - * Stream real-time updates for a task execution - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.StreamTaskUpdates - */ - streamTaskUpdates: { - name: "StreamTaskUpdates", - I: TaskRequest, - O: TaskUpdate, - kind: MethodKind.ServerStreaming, - }, - /** - * Generate a tailored resume for a specific job posting - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.TailorResume - */ - tailorResume: { - name: "TailorResume", - I: ResumeRequest, - O: ResumeResponse, - kind: MethodKind.Unary, - }, - /** - * Generate an essay or cover letter - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.GenerateEssay - */ - generateEssay: { - name: "GenerateEssay", - I: EssayRequest, - O: EssayResponse, - kind: MethodKind.Unary, - }, - } -} as const; - diff --git a/electron/src/generated/ai_orchestrator_pb.ts b/electron/src/generated/ai_orchestrator_pb.ts deleted file mode 100644 index d5459fe..0000000 --- a/electron/src/generated/ai_orchestrator_pb.ts +++ /dev/null @@ -1,360 +0,0 @@ -// @generated by protoc-gen-es v2.2.2 with parameter "target=ts" -// @generated from file ai_orchestrator.proto (package fi.ai.orchestrator.v1, syntax proto3) -/* eslint-disable */ - -import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1"; -import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1"; -import { file_google_protobuf_empty, file_google_protobuf_struct } from "@bufbuild/protobuf/wkt"; -import type { Error } from "./common_pb"; -import { file_common } from "./common_pb"; -import type { JsonObject, Message } from "@bufbuild/protobuf"; - -/** - * Describes the file ai_orchestrator.proto. - */ -export const file_ai_orchestrator: GenFile = /*@__PURE__*/ - fileDesc("ChVhaV9vcmNoZXN0cmF0b3IucHJvdG8SFWZpLmFpLm9yY2hlc3RyYXRvci52MSKXAQoLVGFza1JlcXVlc3QSDwoHdGFza19pZBgBIAEoCRIRCgl0YXNrX3R5cGUYAiABKAkSCwoDdXJsGAMgASgJEigKB2NvbnRleHQYBCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Ei0KDGluc3RydWN0aW9ucxgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QilAEKDFRhc2tSZXNwb25zZRIPCgd0YXNrX2lkGAEgASgJEg4KBnN0YXR1cxgCIAEoCRInCgZyZXN1bHQYAyABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EhYKDnNjcmVlbnNob3RfaWRzGAQgAygJEiIKBWVycm9yGAUgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIqABCgpUYXNrVXBkYXRlEg8KB3Rhc2tfaWQYASABKAkSDgoGc3RhdHVzGAIgASgJEg8KB21lc3NhZ2UYAyABKAkSJQoEZGF0YRgEIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSFQoNc2NyZWVuc2hvdF9pZBgFIAEoCRIiCgVlcnJvchgGIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvciJiCg1SZXN1bWVSZXF1ZXN0EhMKC2pvYl9wb3N0aW5nGAEgASgJEi0KDHVzZXJfcHJvZmlsZRgCIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSDQoFc3R5bGUYAyABKAkiZAoOUmVzdW1lUmVzcG9uc2USFwoPdGFpbG9yZWRfcmVzdW1lGAEgASgJEhUKDW1vZGlmaWNhdGlvbnMYAiADKAkSIgoFZXJyb3IYAyABKAsyEy5maS5jb21tb24udjEuRXJyb3IiiwEKDEVzc2F5UmVxdWVzdBIOCgZwcm9tcHQYASABKAkSLQoMdXNlcl9wcm9maWxlGAIgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIoCgdjb250ZXh0GAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBISCgp3b3JkX2xpbWl0GAQgASgFImoKDUVzc2F5UmVzcG9uc2USDQoFZXNzYXkYASABKAkSEgoKd29yZF9jb3VudBgCIAEoBRISCgprZXlfcG9pbnRzGAMgAygJEiIKBWVycm9yGAQgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yMv8CCg5BSU9yY2hlc3RyYXRvchJWCgtFeGVjdXRlVGFzaxIiLmZpLmFpLm9yY2hlc3RyYXRvci52MS5UYXNrUmVxdWVzdBojLmZpLmFpLm9yY2hlc3RyYXRvci52MS5UYXNrUmVzcG9uc2USXAoRU3RyZWFtVGFza1VwZGF0ZXMSIi5maS5haS5vcmNoZXN0cmF0b3IudjEuVGFza1JlcXVlc3QaIS5maS5haS5vcmNoZXN0cmF0b3IudjEuVGFza1VwZGF0ZTABElsKDFRhaWxvclJlc3VtZRIkLmZpLmFpLm9yY2hlc3RyYXRvci52MS5SZXN1bWVSZXF1ZXN0GiUuZmkuYWkub3JjaGVzdHJhdG9yLnYxLlJlc3VtZVJlc3BvbnNlEloKDUdlbmVyYXRlRXNzYXkSIy5maS5haS5vcmNoZXN0cmF0b3IudjEuRXNzYXlSZXF1ZXN0GiQuZmkuYWkub3JjaGVzdHJhdG9yLnYxLkVzc2F5UmVzcG9uc2VC+QEKGWNvbS5maS5haS5vcmNoZXN0cmF0b3IudjFCE0FpT3JjaGVzdHJhdG9yUHJvdG9QAVpQZ2l0aHViLmNvbS9GaXJlbGlnaHQtSW5ub3ZhdGlvbnMvRmlBcHBseS9wcm90by9haS9vcmNoZXN0cmF0b3IvdjE7b3JjaGVzdHJhdG9ydjGiAgNGQU+qAhVGaS5BaS5PcmNoZXN0cmF0b3IuVjHKAhVGaVxBaVxPcmNoZXN0cmF0b3JcVjHiAiFGaVxBaVxPcmNoZXN0cmF0b3JcVjFcR1BCTWV0YWRhdGHqAhhGaTo6QWk6Ok9yY2hlc3RyYXRvcjo6VjFiBnByb3RvMw", [file_google_protobuf_struct, file_google_protobuf_empty, file_common]); - -/** - * @generated from message fi.ai.orchestrator.v1.TaskRequest - */ -export type TaskRequest = Message<"fi.ai.orchestrator.v1.TaskRequest"> & { - /** - * Unique task identifier - * - * @generated from field: string task_id = 1; - */ - taskId: string; - - /** - * Type of task to execute - * - * @generated from field: string task_type = 2; - */ - taskType: string; - - /** - * Target URL for automation - * - * @generated from field: string url = 3; - */ - url: string; - - /** - * Contextual data (user profile, form data, etc.) - * - * @generated from field: google.protobuf.Struct context = 4; - */ - context?: JsonObject; - - /** - * Specific task instructions - * - * @generated from field: google.protobuf.Struct instructions = 5; - */ - instructions?: JsonObject; -}; - -/** - * Describes the message fi.ai.orchestrator.v1.TaskRequest. - * Use `create(TaskRequestSchema)` to create a new message. - */ -export const TaskRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_ai_orchestrator, 0); - -/** - * @generated from message fi.ai.orchestrator.v1.TaskResponse - */ -export type TaskResponse = Message<"fi.ai.orchestrator.v1.TaskResponse"> & { - /** - * Task identifier - * - * @generated from field: string task_id = 1; - */ - taskId: string; - - /** - * Task status ("pending", "running", "completed", "failed") - * - * @generated from field: string status = 2; - */ - status: string; - - /** - * Task execution result - * - * @generated from field: google.protobuf.Struct result = 3; - */ - result?: JsonObject; - - /** - * IDs of screenshots captured during task - * - * @generated from field: repeated string screenshot_ids = 4; - */ - screenshotIds: string[]; - - /** - * Error details if task failed - * - * @generated from field: fi.common.v1.Error error = 5; - */ - error?: Error; -}; - -/** - * Describes the message fi.ai.orchestrator.v1.TaskResponse. - * Use `create(TaskResponseSchema)` to create a new message. - */ -export const TaskResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_ai_orchestrator, 1); - -/** - * @generated from message fi.ai.orchestrator.v1.TaskUpdate - */ -export type TaskUpdate = Message<"fi.ai.orchestrator.v1.TaskUpdate"> & { - /** - * Task identifier - * - * @generated from field: string task_id = 1; - */ - taskId: string; - - /** - * Current task status - * - * @generated from field: string status = 2; - */ - status: string; - - /** - * Human-readable update message - * - * @generated from field: string message = 3; - */ - message: string; - - /** - * Additional update data - * - * @generated from field: google.protobuf.Struct data = 4; - */ - data?: JsonObject; - - /** - * Screenshot ID if a screenshot was captured - * - * @generated from field: string screenshot_id = 5; - */ - screenshotId: string; - - /** - * Error details if an error occurred - * - * @generated from field: fi.common.v1.Error error = 6; - */ - error?: Error; -}; - -/** - * Describes the message fi.ai.orchestrator.v1.TaskUpdate. - * Use `create(TaskUpdateSchema)` to create a new message. - */ -export const TaskUpdateSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_ai_orchestrator, 2); - -/** - * @generated from message fi.ai.orchestrator.v1.ResumeRequest - */ -export type ResumeRequest = Message<"fi.ai.orchestrator.v1.ResumeRequest"> & { - /** - * Job posting text or URL - * - * @generated from field: string job_posting = 1; - */ - jobPosting: string; - - /** - * User's profile and experience data - * - * @generated from field: google.protobuf.Struct user_profile = 2; - */ - userProfile?: JsonObject; - - /** - * Desired resume style ("modern", "traditional", "technical") - * - * @generated from field: string style = 3; - */ - style: string; -}; - -/** - * Describes the message fi.ai.orchestrator.v1.ResumeRequest. - * Use `create(ResumeRequestSchema)` to create a new message. - */ -export const ResumeRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_ai_orchestrator, 3); - -/** - * @generated from message fi.ai.orchestrator.v1.ResumeResponse - */ -export type ResumeResponse = Message<"fi.ai.orchestrator.v1.ResumeResponse"> & { - /** - * Generated tailored resume (markdown or PDF) - * - * @generated from field: string tailored_resume = 1; - */ - tailoredResume: string; - - /** - * List of modifications made from base resume - * - * @generated from field: repeated string modifications = 2; - */ - modifications: string[]; - - /** - * Error details if generation failed - * - * @generated from field: fi.common.v1.Error error = 3; - */ - error?: Error; -}; - -/** - * Describes the message fi.ai.orchestrator.v1.ResumeResponse. - * Use `create(ResumeResponseSchema)` to create a new message. - */ -export const ResumeResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_ai_orchestrator, 4); - -/** - * @generated from message fi.ai.orchestrator.v1.EssayRequest - */ -export type EssayRequest = Message<"fi.ai.orchestrator.v1.EssayRequest"> & { - /** - * Essay prompt or question - * - * @generated from field: string prompt = 1; - */ - prompt: string; - - /** - * User's profile data - * - * @generated from field: google.protobuf.Struct user_profile = 2; - */ - userProfile?: JsonObject; - - /** - * Additional context (company info, scholarship details, etc.) - * - * @generated from field: google.protobuf.Struct context = 3; - */ - context?: JsonObject; - - /** - * Maximum word count (0 for no limit) - * - * @generated from field: int32 word_limit = 4; - */ - wordLimit: number; -}; - -/** - * Describes the message fi.ai.orchestrator.v1.EssayRequest. - * Use `create(EssayRequestSchema)` to create a new message. - */ -export const EssayRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_ai_orchestrator, 5); - -/** - * @generated from message fi.ai.orchestrator.v1.EssayResponse - */ -export type EssayResponse = Message<"fi.ai.orchestrator.v1.EssayResponse"> & { - /** - * Generated essay text - * - * @generated from field: string essay = 1; - */ - essay: string; - - /** - * Actual word count - * - * @generated from field: int32 word_count = 2; - */ - wordCount: number; - - /** - * Key points covered in the essay - * - * @generated from field: repeated string key_points = 3; - */ - keyPoints: string[]; - - /** - * Error details if generation failed - * - * @generated from field: fi.common.v1.Error error = 4; - */ - error?: Error; -}; - -/** - * Describes the message fi.ai.orchestrator.v1.EssayResponse. - * Use `create(EssayResponseSchema)` to create a new message. - */ -export const EssayResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_ai_orchestrator, 6); - -/** - * AI Orchestrator - Coordinates AI operations and browser automation - * - * @generated from service fi.ai.orchestrator.v1.AIOrchestrator - */ -export const AIOrchestrator: GenService<{ - /** - * Execute a browser automation task (job application, form filling, etc.) - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.ExecuteTask - */ - executeTask: { - methodKind: "unary"; - input: typeof TaskRequestSchema; - output: typeof TaskResponseSchema; - }, - /** - * Stream real-time updates for a task execution - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.StreamTaskUpdates - */ - streamTaskUpdates: { - methodKind: "server_streaming"; - input: typeof TaskRequestSchema; - output: typeof TaskUpdateSchema; - }, - /** - * Generate a tailored resume for a specific job posting - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.TailorResume - */ - tailorResume: { - methodKind: "unary"; - input: typeof ResumeRequestSchema; - output: typeof ResumeResponseSchema; - }, - /** - * Generate an essay or cover letter - * - * @generated from rpc fi.ai.orchestrator.v1.AIOrchestrator.GenerateEssay - */ - generateEssay: { - methodKind: "unary"; - input: typeof EssayRequestSchema; - output: typeof EssayResponseSchema; - }, -}> = /*@__PURE__*/ - serviceDesc(file_ai_orchestrator, 0); - diff --git a/electron/src/generated/api_gateway_connect.ts b/electron/src/generated/api_gateway_connect.ts deleted file mode 100644 index b2bb001..0000000 --- a/electron/src/generated/api_gateway_connect.ts +++ /dev/null @@ -1,52 +0,0 @@ -// @generated by protoc-gen-connect-es v1.6.1 with parameter "target=ts" -// @generated from file api_gateway.proto (package fi.gateway.v1, syntax proto3) -/* eslint-disable */ -// @ts-nocheck - -import { Empty, MethodKind } from "@bufbuild/protobuf"; -import { AutomationRequest, AutomationResponse, HealthCheckResponse, StatusRequest, StatusResponse } from "./api_gateway_pb.js"; - -/** - * API Gateway - Entry point for all client requests - * - * @generated from service fi.gateway.v1.Gateway - */ -export const Gateway = { - typeName: "fi.gateway.v1.Gateway", - methods: { - /** - * Health check endpoint - returns service status and health of dependent services - * - * @generated from rpc fi.gateway.v1.Gateway.HealthCheck - */ - healthCheck: { - name: "HealthCheck", - I: Empty, - O: HealthCheckResponse, - kind: MethodKind.Unary, - }, - /** - * Execute browser automation task (job application, scholarship application, etc.) - * - * @generated from rpc fi.gateway.v1.Gateway.ExecuteAutomation - */ - executeAutomation: { - name: "ExecuteAutomation", - I: AutomationRequest, - O: AutomationResponse, - kind: MethodKind.Unary, - }, - /** - * Get current status of an automation task - * - * @generated from rpc fi.gateway.v1.Gateway.GetAutomationStatus - */ - getAutomationStatus: { - name: "GetAutomationStatus", - I: StatusRequest, - O: StatusResponse, - kind: MethodKind.Unary, - }, - } -} as const; - diff --git a/electron/src/generated/api_gateway_pb.ts b/electron/src/generated/api_gateway_pb.ts deleted file mode 100644 index cf81ceb..0000000 --- a/electron/src/generated/api_gateway_pb.ts +++ /dev/null @@ -1,276 +0,0 @@ -// @generated by protoc-gen-es v2.2.2 with parameter "target=ts" -// @generated from file api_gateway.proto (package fi.gateway.v1, syntax proto3) -/* eslint-disable */ - -import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1"; -import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1"; -import type { EmptySchema } from "@bufbuild/protobuf/wkt"; -import { file_google_protobuf_empty, file_google_protobuf_struct } from "@bufbuild/protobuf/wkt"; -import type { Error } from "./common_pb"; -import { file_common } from "./common_pb"; -import type { JsonObject, Message } from "@bufbuild/protobuf"; - -/** - * Describes the file api_gateway.proto. - */ -export const file_api_gateway: GenFile = /*@__PURE__*/ - fileDesc("ChFhcGlfZ2F0ZXdheS5wcm90bxINZmkuZ2F0ZXdheS52MSK+AQoTSGVhbHRoQ2hlY2tSZXNwb25zZRIOCgZzdGF0dXMYASABKAkSQgoIc2VydmljZXMYAiADKAsyMC5maS5nYXRld2F5LnYxLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmljZXNFbnRyeRIiCgVlcnJvchgDIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvchovCg1TZXJ2aWNlc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEijAEKEUF1dG9tYXRpb25SZXF1ZXN0EgsKA3VybBgBIAEoCRIRCgl0YXNrX3R5cGUYAiABKAkSKAoHY29udGV4dBgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSLQoMaW5zdHJ1Y3Rpb25zGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdCKyAQoSQXV0b21hdGlvblJlc3BvbnNlEg8KB3Rhc2tfaWQYASABKAkSDgoGc3RhdHVzGAIgASgJEicKBnJlc3VsdBgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSLgoLc2NyZWVuc2hvdHMYBCADKAsyGS5maS5nYXRld2F5LnYxLlNjcmVlbnNob3QSIgoFZXJyb3IYBSABKAsyEy5maS5jb21tb24udjEuRXJyb3IiIAoNU3RhdHVzUmVxdWVzdBIPCgd0YXNrX2lkGAEgASgJInwKDlN0YXR1c1Jlc3BvbnNlEg8KB3Rhc2tfaWQYASABKAkSDgoGc3RhdHVzGAIgASgJEiUKBGRhdGEYAyABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EiIKBWVycm9yGAQgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIlUKClNjcmVlbnNob3QSCgoCaWQYASABKAkSEQoJdGltZXN0YW1wGAIgASgJEhMKC2Jhc2U2NF9kYXRhGAMgASgJEhMKC2Rlc2NyaXB0aW9uGAQgASgJMoICCgdHYXRld2F5EkkKC0hlYWx0aENoZWNrEhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5GiIuZmkuZ2F0ZXdheS52MS5IZWFsdGhDaGVja1Jlc3BvbnNlElgKEUV4ZWN1dGVBdXRvbWF0aW9uEiAuZmkuZ2F0ZXdheS52MS5BdXRvbWF0aW9uUmVxdWVzdBohLmZpLmdhdGV3YXkudjEuQXV0b21hdGlvblJlc3BvbnNlElIKE0dldEF1dG9tYXRpb25TdGF0dXMSHC5maS5nYXRld2F5LnYxLlN0YXR1c1JlcXVlc3QaHS5maS5nYXRld2F5LnYxLlN0YXR1c1Jlc3BvbnNlQr8BChFjb20uZmkuZ2F0ZXdheS52MUIPQXBpR2F0ZXdheVByb3RvUAFaQ2dpdGh1Yi5jb20vRmlyZWxpZ2h0LUlubm92YXRpb25zL0ZpQXBwbHkvcHJvdG8vZ2F0ZXdheS92MTtnYXRld2F5djGiAgNGR1iqAg1GaS5HYXRld2F5LlYxygINRmlcR2F0ZXdheVxWMeICGUZpXEdhdGV3YXlcVjFcR1BCTWV0YWRhdGHqAg9GaTo6R2F0ZXdheTo6VjFiBnByb3RvMw", [file_google_protobuf_struct, file_google_protobuf_empty, file_common]); - -/** - * @generated from message fi.gateway.v1.HealthCheckResponse - */ -export type HealthCheckResponse = Message<"fi.gateway.v1.HealthCheckResponse"> & { - /** - * Overall service status ("healthy", "degraded", "unhealthy") - * - * @generated from field: string status = 1; - */ - status: string; - - /** - * Health status of dependent services - * - * @generated from field: map services = 2; - */ - services: { [key: string]: string }; - - /** - * Error details if health check failed - * - * @generated from field: fi.common.v1.Error error = 3; - */ - error?: Error; -}; - -/** - * Describes the message fi.gateway.v1.HealthCheckResponse. - * Use `create(HealthCheckResponseSchema)` to create a new message. - */ -export const HealthCheckResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_api_gateway, 0); - -/** - * @generated from message fi.gateway.v1.AutomationRequest - */ -export type AutomationRequest = Message<"fi.gateway.v1.AutomationRequest"> & { - /** - * Target URL to automate (e.g., job application page) - * - * @generated from field: string url = 1; - */ - url: string; - - /** - * Type of automation task ("job_application", "scholarship_application") - * - * @generated from field: string task_type = 2; - */ - taskType: string; - - /** - * User data and context (resume, profile, etc.) - * - * @generated from field: google.protobuf.Struct context = 3; - */ - context?: JsonObject; - - /** - * Specific instructions or preferences - * - * @generated from field: google.protobuf.Struct instructions = 4; - */ - instructions?: JsonObject; -}; - -/** - * Describes the message fi.gateway.v1.AutomationRequest. - * Use `create(AutomationRequestSchema)` to create a new message. - */ -export const AutomationRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_api_gateway, 1); - -/** - * @generated from message fi.gateway.v1.AutomationResponse - */ -export type AutomationResponse = Message<"fi.gateway.v1.AutomationResponse"> & { - /** - * Unique task identifier for tracking - * - * @generated from field: string task_id = 1; - */ - taskId: string; - - /** - * Current task status ("pending", "running", "completed", "failed") - * - * @generated from field: string status = 2; - */ - status: string; - - /** - * Task result data (application details, confirmation numbers, etc.) - * - * @generated from field: google.protobuf.Struct result = 3; - */ - result?: JsonObject; - - /** - * Screenshots captured during automation - * - * @generated from field: repeated fi.gateway.v1.Screenshot screenshots = 4; - */ - screenshots: Screenshot[]; - - /** - * Error details if task failed - * - * @generated from field: fi.common.v1.Error error = 5; - */ - error?: Error; -}; - -/** - * Describes the message fi.gateway.v1.AutomationResponse. - * Use `create(AutomationResponseSchema)` to create a new message. - */ -export const AutomationResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_api_gateway, 2); - -/** - * @generated from message fi.gateway.v1.StatusRequest - */ -export type StatusRequest = Message<"fi.gateway.v1.StatusRequest"> & { - /** - * Task ID to query status for - * - * @generated from field: string task_id = 1; - */ - taskId: string; -}; - -/** - * Describes the message fi.gateway.v1.StatusRequest. - * Use `create(StatusRequestSchema)` to create a new message. - */ -export const StatusRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_api_gateway, 3); - -/** - * @generated from message fi.gateway.v1.StatusResponse - */ -export type StatusResponse = Message<"fi.gateway.v1.StatusResponse"> & { - /** - * Task identifier - * - * @generated from field: string task_id = 1; - */ - taskId: string; - - /** - * Current status ("pending", "running", "completed", "failed") - * - * @generated from field: string status = 2; - */ - status: string; - - /** - * Additional status data - * - * @generated from field: google.protobuf.Struct data = 3; - */ - data?: JsonObject; - - /** - * Error details if task failed - * - * @generated from field: fi.common.v1.Error error = 4; - */ - error?: Error; -}; - -/** - * Describes the message fi.gateway.v1.StatusResponse. - * Use `create(StatusResponseSchema)` to create a new message. - */ -export const StatusResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_api_gateway, 4); - -/** - * @generated from message fi.gateway.v1.Screenshot - */ -export type Screenshot = Message<"fi.gateway.v1.Screenshot"> & { - /** - * Unique screenshot identifier - * - * @generated from field: string id = 1; - */ - id: string; - - /** - * ISO 8601 timestamp when screenshot was taken - * - * @generated from field: string timestamp = 2; - */ - timestamp: string; - - /** - * Base64-encoded PNG image data - * - * @generated from field: string base64_data = 3; - */ - base64Data: string; - - /** - * Description of what the screenshot shows - * - * @generated from field: string description = 4; - */ - description: string; -}; - -/** - * Describes the message fi.gateway.v1.Screenshot. - * Use `create(ScreenshotSchema)` to create a new message. - */ -export const ScreenshotSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_api_gateway, 5); - -/** - * API Gateway - Entry point for all client requests - * - * @generated from service fi.gateway.v1.Gateway - */ -export const Gateway: GenService<{ - /** - * Health check endpoint - returns service status and health of dependent services - * - * @generated from rpc fi.gateway.v1.Gateway.HealthCheck - */ - healthCheck: { - methodKind: "unary"; - input: typeof EmptySchema; - output: typeof HealthCheckResponseSchema; - }, - /** - * Execute browser automation task (job application, scholarship application, etc.) - * - * @generated from rpc fi.gateway.v1.Gateway.ExecuteAutomation - */ - executeAutomation: { - methodKind: "unary"; - input: typeof AutomationRequestSchema; - output: typeof AutomationResponseSchema; - }, - /** - * Get current status of an automation task - * - * @generated from rpc fi.gateway.v1.Gateway.GetAutomationStatus - */ - getAutomationStatus: { - methodKind: "unary"; - input: typeof StatusRequestSchema; - output: typeof StatusResponseSchema; - }, -}> = /*@__PURE__*/ - serviceDesc(file_api_gateway, 0); - diff --git a/electron/src/generated/common_pb.ts b/electron/src/generated/common_pb.ts deleted file mode 100644 index b0806f9..0000000 --- a/electron/src/generated/common_pb.ts +++ /dev/null @@ -1,449 +0,0 @@ -// @generated by protoc-gen-es v2.2.2 with parameter "target=ts" -// @generated from file common.proto (package fi.common.v1, syntax proto3) -/* eslint-disable */ - -import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1"; -import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1"; -import type { Timestamp } from "@bufbuild/protobuf/wkt"; -import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt"; -import type { Message } from "@bufbuild/protobuf"; - -/** - * Describes the file common.proto. - */ -export const file_common: GenFile = /*@__PURE__*/ - fileDesc("Cgxjb21tb24ucHJvdG8SDGZpLmNvbW1vbi52MSK7AgoFRXJyb3ISJQoEY29kZRgBIAEoDjIXLmZpLmNvbW1vbi52MS5FcnJvckNvZGUSDwoHbWVzc2FnZRgCIAEoCRIxCgdkZXRhaWxzGAMgAygLMiAuZmkuY29tbW9uLnYxLkVycm9yLkRldGFpbHNFbnRyeRIQCgh0cmFjZV9pZBgEIAEoCRIwCg1lcnJvcl9kZXRhaWxzGAUgAygLMhkuZmkuY29tbW9uLnYxLkVycm9yRGV0YWlsEi0KCXRpbWVzdGFtcBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASDwoHc2VydmljZRgHIAEoCRITCgtzdGFja190cmFjZRgIIAEoCRouCgxEZXRhaWxzRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASI/CgtFcnJvckRldGFpbBINCgVmaWVsZBgBIAEoCRINCgVpc3N1ZRgCIAEoCRISCgpzdWdnZXN0aW9uGAMgASgJIj0KBlN0YXR1cxIPCgdzdWNjZXNzGAEgASgIEiIKBWVycm9yGAIgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIn0KCFBhZ2VJbmZvEgwKBHBhZ2UYASABKAUSEQoJcGFnZV9zaXplGAIgASgFEhMKC3RvdGFsX2l0ZW1zGAMgASgDEhMKC3RvdGFsX3BhZ2VzGAQgASgFEhAKCGhhc19uZXh0GAUgASgIEhQKDGhhc19wcmV2aW91cxgGIAEoCCKMAQoPUmVxdWVzdE1ldGFkYXRhEhIKCnJlcXVlc3RfaWQYASABKAkSEgoKdXNlcl9hZ2VudBgCIAEoCRIRCgljbGllbnRfaXAYAyABKAkSLQoJdGltZXN0YW1wGAQgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIPCgd1c2VyX2lkGAUgASgJKvwFCglFcnJvckNvZGUSGgoWRVJST1JfQ09ERV9VTlNQRUNJRklFRBAAEh8KG0VSUk9SX0NPREVfSU5WQUxJRF9BUkdVTUVOVBABEh4KGkVSUk9SX0NPREVfVU5BVVRIRU5USUNBVEVEEAISIAocRVJST1JfQ09ERV9QRVJNSVNTSU9OX0RFTklFRBADEhgKFEVSUk9SX0NPREVfTk9UX0ZPVU5EEAQSHQoZRVJST1JfQ09ERV9BTFJFQURZX0VYSVNUUxAFEiEKHUVSUk9SX0NPREVfUkVTT1VSQ0VfRVhIQVVTVEVEEAYSIgoeRVJST1JfQ09ERV9GQUlMRURfUFJFQ09ORElUSU9OEAcSFgoSRVJST1JfQ09ERV9BQk9SVEVEEAgSGwoXRVJST1JfQ09ERV9PVVRfT0ZfUkFOR0UQCRIXChNFUlJPUl9DT0RFX0lOVEVSTkFMEGQSGgoWRVJST1JfQ09ERV9VTkFWQUlMQUJMRRBlEiAKHEVSUk9SX0NPREVfREVBRExJTkVfRVhDRUVERUQQZhIcChhFUlJPUl9DT0RFX1VOSU1QTEVNRU5URUQQZxIYChRFUlJPUl9DT0RFX0RBVEFfTE9TUxBoEiEKHEVSUk9SX0NPREVfVkFMSURBVElPTl9GQUlMRUQQyAESGwoWRVJST1JfQ09ERV9UQVNLX0ZBSUxFRBDJARIZChRFUlJPUl9DT0RFX0xMTV9FUlJPUhDKARIdChhFUlJPUl9DT0RFX0JST1dTRVJfRVJST1IQywESGQoURVJST1JfQ09ERV9SQUdfRVJST1IQzAESHQoYRVJST1JfQ09ERV9QQVJTSU5HX0VSUk9SEM0BEiAKG0VSUk9SX0NPREVfTkFWSUdBVElPTl9FUlJPUhDOARIfChpFUlJPUl9DT0RFX0ZPUk1fRklMTF9FUlJPUhDPARIXChJFUlJPUl9DT0RFX1RJTUVPVVQQ0AESHAoXRVJST1JfQ09ERV9SQVRFX0xJTUlURUQQ0QFCtAEKEGNvbS5maS5jb21tb24udjFCC0NvbW1vblByb3RvUAFaQWdpdGh1Yi5jb20vRmlyZWxpZ2h0LUlubm92YXRpb25zL0ZpQXBwbHkvcHJvdG8vY29tbW9uL3YxO2NvbW1vbnYxogIDRkNYqgIMRmkuQ29tbW9uLlYxygIMRmlcQ29tbW9uXFYx4gIYRmlcQ29tbW9uXFYxXEdQQk1ldGFkYXRh6gIORmk6OkNvbW1vbjo6VjFiBnByb3RvMw", [file_google_protobuf_timestamp]); - -/** - * Detailed error information - * - * @generated from message fi.common.v1.Error - */ -export type Error = Message<"fi.common.v1.Error"> & { - /** - * Error code for programmatic handling - * - * @generated from field: fi.common.v1.ErrorCode code = 1; - */ - code: ErrorCode; - - /** - * Human-readable error message - * - * @generated from field: string message = 2; - */ - message: string; - - /** - * Additional error context (key-value pairs) - * - * @generated from field: map details = 3; - */ - details: { [key: string]: string }; - - /** - * Distributed tracing ID for debugging - * - * @generated from field: string trace_id = 4; - */ - traceId: string; - - /** - * Detailed field-level errors (for validation) - * - * @generated from field: repeated fi.common.v1.ErrorDetail error_details = 5; - */ - errorDetails: ErrorDetail[]; - - /** - * Timestamp when error occurred - * - * @generated from field: google.protobuf.Timestamp timestamp = 6; - */ - timestamp?: Timestamp; - - /** - * Service that generated the error - * - * @generated from field: string service = 7; - */ - service: string; - - /** - * Stack trace (only in development/debug mode) - * - * @generated from field: string stack_trace = 8; - */ - stackTrace: string; -}; - -/** - * Describes the message fi.common.v1.Error. - * Use `create(ErrorSchema)` to create a new message. - */ -export const ErrorSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_common, 0); - -/** - * Field-level error detail - * - * @generated from message fi.common.v1.ErrorDetail - */ -export type ErrorDetail = Message<"fi.common.v1.ErrorDetail"> & { - /** - * Field path (e.g., "user.email", "items[0].price") - * - * @generated from field: string field = 1; - */ - field: string; - - /** - * Issue description - * - * @generated from field: string issue = 2; - */ - issue: string; - - /** - * Suggestion for fixing the issue - * - * @generated from field: string suggestion = 3; - */ - suggestion: string; -}; - -/** - * Describes the message fi.common.v1.ErrorDetail. - * Use `create(ErrorDetailSchema)` to create a new message. - */ -export const ErrorDetailSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_common, 1); - -/** - * Standard response wrapper for operations - * - * @generated from message fi.common.v1.Status - */ -export type Status = Message<"fi.common.v1.Status"> & { - /** - * Operation success flag - * - * @generated from field: bool success = 1; - */ - success: boolean; - - /** - * Error details (null if success = true) - * - * @generated from field: fi.common.v1.Error error = 2; - */ - error?: Error; -}; - -/** - * Describes the message fi.common.v1.Status. - * Use `create(StatusSchema)` to create a new message. - */ -export const StatusSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_common, 2); - -/** - * Pagination metadata - * - * @generated from message fi.common.v1.PageInfo - */ -export type PageInfo = Message<"fi.common.v1.PageInfo"> & { - /** - * Current page number (1-indexed) - * - * @generated from field: int32 page = 1; - */ - page: number; - - /** - * Items per page - * - * @generated from field: int32 page_size = 2; - */ - pageSize: number; - - /** - * Total number of items - * - * @generated from field: int64 total_items = 3; - */ - totalItems: bigint; - - /** - * Total number of pages - * - * @generated from field: int32 total_pages = 4; - */ - totalPages: number; - - /** - * Has next page - * - * @generated from field: bool has_next = 5; - */ - hasNext: boolean; - - /** - * Has previous page - * - * @generated from field: bool has_previous = 6; - */ - hasPrevious: boolean; -}; - -/** - * Describes the message fi.common.v1.PageInfo. - * Use `create(PageInfoSchema)` to create a new message. - */ -export const PageInfoSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_common, 3); - -/** - * Request metadata for tracing and monitoring - * - * @generated from message fi.common.v1.RequestMetadata - */ -export type RequestMetadata = Message<"fi.common.v1.RequestMetadata"> & { - /** - * Unique request ID - * - * @generated from field: string request_id = 1; - */ - requestId: string; - - /** - * Client user agent - * - * @generated from field: string user_agent = 2; - */ - userAgent: string; - - /** - * Client IP address - * - * @generated from field: string client_ip = 3; - */ - clientIp: string; - - /** - * Request timestamp - * - * @generated from field: google.protobuf.Timestamp timestamp = 4; - */ - timestamp?: Timestamp; - - /** - * User ID (if authenticated) - * - * @generated from field: string user_id = 5; - */ - userId: string; -}; - -/** - * Describes the message fi.common.v1.RequestMetadata. - * Use `create(RequestMetadataSchema)` to create a new message. - */ -export const RequestMetadataSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_common, 4); - -/** - * Standard error codes across all FiApply services - * Aligned with gRPC status codes but extended for business logic - * - * @generated from enum fi.common.v1.ErrorCode - */ -export enum ErrorCode { - /** - * Unspecified error code (default value) - * - * @generated from enum value: ERROR_CODE_UNSPECIFIED = 0; - */ - UNSPECIFIED = 0, - - /** - * Client errors (4xx equivalent) - range 1-99 - * - * Invalid request parameters - * - * @generated from enum value: ERROR_CODE_INVALID_ARGUMENT = 1; - */ - INVALID_ARGUMENT = 1, - - /** - * Authentication required - * - * @generated from enum value: ERROR_CODE_UNAUTHENTICATED = 2; - */ - UNAUTHENTICATED = 2, - - /** - * Insufficient permissions - * - * @generated from enum value: ERROR_CODE_PERMISSION_DENIED = 3; - */ - PERMISSION_DENIED = 3, - - /** - * Resource not found - * - * @generated from enum value: ERROR_CODE_NOT_FOUND = 4; - */ - NOT_FOUND = 4, - - /** - * Resource already exists - * - * @generated from enum value: ERROR_CODE_ALREADY_EXISTS = 5; - */ - ALREADY_EXISTS = 5, - - /** - * Rate limit or quota exceeded - * - * @generated from enum value: ERROR_CODE_RESOURCE_EXHAUSTED = 6; - */ - RESOURCE_EXHAUSTED = 6, - - /** - * Request precondition failed - * - * @generated from enum value: ERROR_CODE_FAILED_PRECONDITION = 7; - */ - FAILED_PRECONDITION = 7, - - /** - * Operation aborted - * - * @generated from enum value: ERROR_CODE_ABORTED = 8; - */ - ABORTED = 8, - - /** - * Value out of valid range - * - * @generated from enum value: ERROR_CODE_OUT_OF_RANGE = 9; - */ - OUT_OF_RANGE = 9, - - /** - * Server errors (5xx equivalent) - range 100-199 - * - * Internal server error - * - * @generated from enum value: ERROR_CODE_INTERNAL = 100; - */ - INTERNAL = 100, - - /** - * Service unavailable - * - * @generated from enum value: ERROR_CODE_UNAVAILABLE = 101; - */ - UNAVAILABLE = 101, - - /** - * Request timeout - * - * @generated from enum value: ERROR_CODE_DEADLINE_EXCEEDED = 102; - */ - DEADLINE_EXCEEDED = 102, - - /** - * Feature not implemented - * - * @generated from enum value: ERROR_CODE_UNIMPLEMENTED = 103; - */ - UNIMPLEMENTED = 103, - - /** - * Unrecoverable data loss - * - * @generated from enum value: ERROR_CODE_DATA_LOSS = 104; - */ - DATA_LOSS = 104, - - /** - * Business logic errors - range 200-299 - * - * Request validation failed - * - * @generated from enum value: ERROR_CODE_VALIDATION_FAILED = 200; - */ - VALIDATION_FAILED = 200, - - /** - * Task execution failed - * - * @generated from enum value: ERROR_CODE_TASK_FAILED = 201; - */ - TASK_FAILED = 201, - - /** - * LLM service error - * - * @generated from enum value: ERROR_CODE_LLM_ERROR = 202; - */ - LLM_ERROR = 202, - - /** - * Browser automation error - * - * @generated from enum value: ERROR_CODE_BROWSER_ERROR = 203; - */ - BROWSER_ERROR = 203, - - /** - * RAG engine error - * - * @generated from enum value: ERROR_CODE_RAG_ERROR = 204; - */ - RAG_ERROR = 204, - - /** - * Content parsing error - * - * @generated from enum value: ERROR_CODE_PARSING_ERROR = 205; - */ - PARSING_ERROR = 205, - - /** - * Browser navigation error - * - * @generated from enum value: ERROR_CODE_NAVIGATION_ERROR = 206; - */ - NAVIGATION_ERROR = 206, - - /** - * Form filling error - * - * @generated from enum value: ERROR_CODE_FORM_FILL_ERROR = 207; - */ - FORM_FILL_ERROR = 207, - - /** - * Operation timeout - * - * @generated from enum value: ERROR_CODE_TIMEOUT = 208; - */ - TIMEOUT = 208, - - /** - * Rate limit exceeded - * - * @generated from enum value: ERROR_CODE_RATE_LIMITED = 209; - */ - RATE_LIMITED = 209, -} - -/** - * Describes the enum fi.common.v1.ErrorCode. - */ -export const ErrorCodeSchema: GenEnum = /*@__PURE__*/ - enumDesc(file_common, 0); - diff --git a/electron/src/generated/llm_manager_connect.ts b/electron/src/generated/llm_manager_connect.ts deleted file mode 100644 index e7e2e09..0000000 --- a/electron/src/generated/llm_manager_connect.ts +++ /dev/null @@ -1,63 +0,0 @@ -// @generated by protoc-gen-connect-es v1.6.1 with parameter "target=ts" -// @generated from file llm_manager.proto (package fi.llm.v1, syntax proto3) -/* eslint-disable */ -// @ts-nocheck - -import { CompletionChunk, CompletionRequest, CompletionResponse, ListModelsRequest, ListModelsResponse, SwitchModelRequest, SwitchModelResponse } from "./llm_manager_pb.js"; -import { MethodKind } from "@bufbuild/protobuf"; - -/** - * LLM Manager - Manages LLM interactions (Ollama & OpenRouter) - * - * @generated from service fi.llm.v1.LLMManager - */ -export const LLMManager = { - typeName: "fi.llm.v1.LLMManager", - methods: { - /** - * Generate a text completion from LLM - * - * @generated from rpc fi.llm.v1.LLMManager.GenerateCompletion - */ - generateCompletion: { - name: "GenerateCompletion", - I: CompletionRequest, - O: CompletionResponse, - kind: MethodKind.Unary, - }, - /** - * Stream a text completion from LLM with real-time chunks - * - * @generated from rpc fi.llm.v1.LLMManager.StreamCompletion - */ - streamCompletion: { - name: "StreamCompletion", - I: CompletionRequest, - O: CompletionChunk, - kind: MethodKind.ServerStreaming, - }, - /** - * List available LLM models from all providers - * - * @generated from rpc fi.llm.v1.LLMManager.ListModels - */ - listModels: { - name: "ListModels", - I: ListModelsRequest, - O: ListModelsResponse, - kind: MethodKind.Unary, - }, - /** - * Switch the active LLM model - * - * @generated from rpc fi.llm.v1.LLMManager.SwitchModel - */ - switchModel: { - name: "SwitchModel", - I: SwitchModelRequest, - O: SwitchModelResponse, - kind: MethodKind.Unary, - }, - } -} as const; - diff --git a/electron/src/generated/llm_manager_pb.ts b/electron/src/generated/llm_manager_pb.ts deleted file mode 100644 index c943f09..0000000 --- a/electron/src/generated/llm_manager_pb.ts +++ /dev/null @@ -1,363 +0,0 @@ -// @generated by protoc-gen-es v2.2.2 with parameter "target=ts" -// @generated from file llm_manager.proto (package fi.llm.v1, syntax proto3) -/* eslint-disable */ - -import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1"; -import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1"; -import { file_google_protobuf_empty, file_google_protobuf_struct } from "@bufbuild/protobuf/wkt"; -import type { Error } from "./common_pb"; -import { file_common } from "./common_pb"; -import type { JsonObject, Message as Message$1 } from "@bufbuild/protobuf"; - -/** - * Describes the file llm_manager.proto. - */ -export const file_llm_manager: GenFile = /*@__PURE__*/ - fileDesc("ChFsbG1fbWFuYWdlci5wcm90bxIJZmkubGxtLnYxIqgBChFDb21wbGV0aW9uUmVxdWVzdBIOCgZwcm9tcHQYASABKAkSDQoFbW9kZWwYAiABKAkSKwoKcGFyYW1ldGVycxgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSMAoUY29udmVyc2F0aW9uX2hpc3RvcnkYBCADKAsyEi5maS5sbG0udjEuTWVzc2FnZRIVCg1zeXN0ZW1fcHJvbXB0GAUgASgJIp0BChJDb21wbGV0aW9uUmVzcG9uc2USDwoHY29udGVudBgBIAEoCRISCgptb2RlbF91c2VkGAIgASgJEhMKC3Rva2Vuc191c2VkGAMgASgFEikKCG1ldGFkYXRhGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIiCgVlcnJvchgFIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvciJYCg9Db21wbGV0aW9uQ2h1bmsSDwoHY29udGVudBgBIAEoCRIQCghpc19maW5hbBgCIAEoCBIiCgVlcnJvchgDIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvciIoCgdNZXNzYWdlEgwKBHJvbGUYASABKAkSDwoHY29udGVudBgCIAEoCSIlChFMaXN0TW9kZWxzUmVxdWVzdBIQCghwcm92aWRlchgBIAEoCSJeChJMaXN0TW9kZWxzUmVzcG9uc2USJAoGbW9kZWxzGAEgAygLMhQuZmkubGxtLnYxLk1vZGVsSW5mbxIiCgVlcnJvchgCIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvciJ8CglNb2RlbEluZm8SCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRIQCghwcm92aWRlchgDIAEoCRIUCgxpc19hdmFpbGFibGUYBCABKAgSLQoMY2FwYWJpbGl0aWVzGAUgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdCImChJTd2l0Y2hNb2RlbFJlcXVlc3QSEAoIbW9kZWxfaWQYASABKAkiYAoTU3dpdGNoTW9kZWxSZXNwb25zZRIPCgdzdWNjZXNzGAEgASgIEhQKDGFjdGl2ZV9tb2RlbBgCIAEoCRIiCgVlcnJvchgDIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvcjLIAgoKTExNTWFuYWdlchJRChJHZW5lcmF0ZUNvbXBsZXRpb24SHC5maS5sbG0udjEuQ29tcGxldGlvblJlcXVlc3QaHS5maS5sbG0udjEuQ29tcGxldGlvblJlc3BvbnNlEk4KEFN0cmVhbUNvbXBsZXRpb24SHC5maS5sbG0udjEuQ29tcGxldGlvblJlcXVlc3QaGi5maS5sbG0udjEuQ29tcGxldGlvbkNodW5rMAESSQoKTGlzdE1vZGVscxIcLmZpLmxsbS52MS5MaXN0TW9kZWxzUmVxdWVzdBodLmZpLmxsbS52MS5MaXN0TW9kZWxzUmVzcG9uc2USTAoLU3dpdGNoTW9kZWwSHS5maS5sbG0udjEuU3dpdGNoTW9kZWxSZXF1ZXN0Gh4uZmkubGxtLnYxLlN3aXRjaE1vZGVsUmVzcG9uc2VCowEKDWNvbS5maS5sbG0udjFCD0xsbU1hbmFnZXJQcm90b1ABWjtnaXRodWIuY29tL0ZpcmVsaWdodC1Jbm5vdmF0aW9ucy9GaUFwcGx5L3Byb3RvL2xsbS92MTtsbG12MaICA0ZMWKoCCUZpLkxsbS5WMcoCCUZpXExsbVxWMeICFUZpXExsbVxWMVxHUEJNZXRhZGF0YeoCC0ZpOjpMbG06OlYxYgZwcm90bzM", [file_google_protobuf_struct, file_google_protobuf_empty, file_common]); - -/** - * @generated from message fi.llm.v1.CompletionRequest - */ -export type CompletionRequest = Message$1<"fi.llm.v1.CompletionRequest"> & { - /** - * User's prompt or query - * - * @generated from field: string prompt = 1; - */ - prompt: string; - - /** - * Model to use (optional, uses default if not specified) - * - * @generated from field: string model = 2; - */ - model: string; - - /** - * Model parameters (temperature, max_tokens, top_p, etc.) - * - * @generated from field: google.protobuf.Struct parameters = 3; - */ - parameters?: JsonObject; - - /** - * Conversation history for context - * - * @generated from field: repeated fi.llm.v1.Message conversation_history = 4; - */ - conversationHistory: Message[]; - - /** - * System prompt for model behavior - * - * @generated from field: string system_prompt = 5; - */ - systemPrompt: string; -}; - -/** - * Describes the message fi.llm.v1.CompletionRequest. - * Use `create(CompletionRequestSchema)` to create a new message. - */ -export const CompletionRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 0); - -/** - * @generated from message fi.llm.v1.CompletionResponse - */ -export type CompletionResponse = Message$1<"fi.llm.v1.CompletionResponse"> & { - /** - * Generated completion text - * - * @generated from field: string content = 1; - */ - content: string; - - /** - * Model that was used for generation - * - * @generated from field: string model_used = 2; - */ - modelUsed: string; - - /** - * Number of tokens consumed - * - * @generated from field: int32 tokens_used = 3; - */ - tokensUsed: number; - - /** - * Additional metadata (finish_reason, etc.) - * - * @generated from field: google.protobuf.Struct metadata = 4; - */ - metadata?: JsonObject; - - /** - * Error details if generation failed - * - * @generated from field: fi.common.v1.Error error = 5; - */ - error?: Error; -}; - -/** - * Describes the message fi.llm.v1.CompletionResponse. - * Use `create(CompletionResponseSchema)` to create a new message. - */ -export const CompletionResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 1); - -/** - * @generated from message fi.llm.v1.CompletionChunk - */ -export type CompletionChunk = Message$1<"fi.llm.v1.CompletionChunk"> & { - /** - * Chunk of generated text - * - * @generated from field: string content = 1; - */ - content: string; - - /** - * Whether this is the final chunk - * - * @generated from field: bool is_final = 2; - */ - isFinal: boolean; - - /** - * Error details if streaming failed - * - * @generated from field: fi.common.v1.Error error = 3; - */ - error?: Error; -}; - -/** - * Describes the message fi.llm.v1.CompletionChunk. - * Use `create(CompletionChunkSchema)` to create a new message. - */ -export const CompletionChunkSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 2); - -/** - * @generated from message fi.llm.v1.Message - */ -export type Message = Message$1<"fi.llm.v1.Message"> & { - /** - * Message role ("user", "assistant", "system") - * - * @generated from field: string role = 1; - */ - role: string; - - /** - * Message content - * - * @generated from field: string content = 2; - */ - content: string; -}; - -/** - * Describes the message fi.llm.v1.Message. - * Use `create(MessageSchema)` to create a new message. - */ -export const MessageSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 3); - -/** - * @generated from message fi.llm.v1.ListModelsRequest - */ -export type ListModelsRequest = Message$1<"fi.llm.v1.ListModelsRequest"> & { - /** - * Provider filter ("ollama", "openrouter", "all") - * - * @generated from field: string provider = 1; - */ - provider: string; -}; - -/** - * Describes the message fi.llm.v1.ListModelsRequest. - * Use `create(ListModelsRequestSchema)` to create a new message. - */ -export const ListModelsRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 4); - -/** - * @generated from message fi.llm.v1.ListModelsResponse - */ -export type ListModelsResponse = Message$1<"fi.llm.v1.ListModelsResponse"> & { - /** - * Available models from requested provider(s) - * - * @generated from field: repeated fi.llm.v1.ModelInfo models = 1; - */ - models: ModelInfo[]; - - /** - * Error details if listing failed - * - * @generated from field: fi.common.v1.Error error = 2; - */ - error?: Error; -}; - -/** - * Describes the message fi.llm.v1.ListModelsResponse. - * Use `create(ListModelsResponseSchema)` to create a new message. - */ -export const ListModelsResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 5); - -/** - * @generated from message fi.llm.v1.ModelInfo - */ -export type ModelInfo = Message$1<"fi.llm.v1.ModelInfo"> & { - /** - * Unique model identifier - * - * @generated from field: string id = 1; - */ - id: string; - - /** - * Human-readable model name - * - * @generated from field: string name = 2; - */ - name: string; - - /** - * Provider hosting the model - * - * @generated from field: string provider = 3; - */ - provider: string; - - /** - * Whether the model is currently available - * - * @generated from field: bool is_available = 4; - */ - isAvailable: boolean; - - /** - * Model capabilities (max_tokens, supports_streaming, etc.) - * - * @generated from field: google.protobuf.Struct capabilities = 5; - */ - capabilities?: JsonObject; -}; - -/** - * Describes the message fi.llm.v1.ModelInfo. - * Use `create(ModelInfoSchema)` to create a new message. - */ -export const ModelInfoSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 6); - -/** - * @generated from message fi.llm.v1.SwitchModelRequest - */ -export type SwitchModelRequest = Message$1<"fi.llm.v1.SwitchModelRequest"> & { - /** - * Model ID to switch to - * - * @generated from field: string model_id = 1; - */ - modelId: string; -}; - -/** - * Describes the message fi.llm.v1.SwitchModelRequest. - * Use `create(SwitchModelRequestSchema)` to create a new message. - */ -export const SwitchModelRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 7); - -/** - * @generated from message fi.llm.v1.SwitchModelResponse - */ -export type SwitchModelResponse = Message$1<"fi.llm.v1.SwitchModelResponse"> & { - /** - * Whether the switch was successful - * - * @generated from field: bool success = 1; - */ - success: boolean; - - /** - * Currently active model ID - * - * @generated from field: string active_model = 2; - */ - activeModel: string; - - /** - * Error details if switch failed - * - * @generated from field: fi.common.v1.Error error = 3; - */ - error?: Error; -}; - -/** - * Describes the message fi.llm.v1.SwitchModelResponse. - * Use `create(SwitchModelResponseSchema)` to create a new message. - */ -export const SwitchModelResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_llm_manager, 8); - -/** - * LLM Manager - Manages LLM interactions (Ollama & OpenRouter) - * - * @generated from service fi.llm.v1.LLMManager - */ -export const LLMManager: GenService<{ - /** - * Generate a text completion from LLM - * - * @generated from rpc fi.llm.v1.LLMManager.GenerateCompletion - */ - generateCompletion: { - methodKind: "unary"; - input: typeof CompletionRequestSchema; - output: typeof CompletionResponseSchema; - }, - /** - * Stream a text completion from LLM with real-time chunks - * - * @generated from rpc fi.llm.v1.LLMManager.StreamCompletion - */ - streamCompletion: { - methodKind: "server_streaming"; - input: typeof CompletionRequestSchema; - output: typeof CompletionChunkSchema; - }, - /** - * List available LLM models from all providers - * - * @generated from rpc fi.llm.v1.LLMManager.ListModels - */ - listModels: { - methodKind: "unary"; - input: typeof ListModelsRequestSchema; - output: typeof ListModelsResponseSchema; - }, - /** - * Switch the active LLM model - * - * @generated from rpc fi.llm.v1.LLMManager.SwitchModel - */ - switchModel: { - methodKind: "unary"; - input: typeof SwitchModelRequestSchema; - output: typeof SwitchModelResponseSchema; - }, -}> = /*@__PURE__*/ - serviceDesc(file_llm_manager, 0); - diff --git a/electron/src/generated/rag_engine_connect.ts b/electron/src/generated/rag_engine_connect.ts deleted file mode 100644 index f5bf7a9..0000000 --- a/electron/src/generated/rag_engine_connect.ts +++ /dev/null @@ -1,63 +0,0 @@ -// @generated by protoc-gen-connect-es v1.6.1 with parameter "target=ts" -// @generated from file rag_engine.proto (package fi.rag.v1, syntax proto3) -/* eslint-disable */ -// @ts-nocheck - -import { EmbeddingRequest, EmbeddingResponse, RetrieveRequest, RetrieveResponse, SearchRequest, SearchResponse, StoreDocumentRequest, StoreDocumentResponse } from "./rag_engine_pb.js"; -import { MethodKind } from "@bufbuild/protobuf"; - -/** - * RAG Engine - Retrieval-Augmented Generation processing - * - * @generated from service fi.rag.v1.RAGEngine - */ -export const RAGEngine = { - typeName: "fi.rag.v1.RAGEngine", - methods: { - /** - * Store document or webpage content with embeddings - * - * @generated from rpc fi.rag.v1.RAGEngine.StoreDocument - */ - storeDocument: { - name: "StoreDocument", - I: StoreDocumentRequest, - O: StoreDocumentResponse, - kind: MethodKind.Unary, - }, - /** - * Retrieve relevant context for a query using vector similarity - * - * @generated from rpc fi.rag.v1.RAGEngine.RetrieveContext - */ - retrieveContext: { - name: "RetrieveContext", - I: RetrieveRequest, - O: RetrieveResponse, - kind: MethodKind.Unary, - }, - /** - * Generate embeddings for text - * - * @generated from rpc fi.rag.v1.RAGEngine.GenerateEmbedding - */ - generateEmbedding: { - name: "GenerateEmbedding", - I: EmbeddingRequest, - O: EmbeddingResponse, - kind: MethodKind.Unary, - }, - /** - * Perform semantic search across stored documents - * - * @generated from rpc fi.rag.v1.RAGEngine.SemanticSearch - */ - semanticSearch: { - name: "SemanticSearch", - I: SearchRequest, - O: SearchResponse, - kind: MethodKind.Unary, - }, - } -} as const; - diff --git a/electron/src/generated/rag_engine_pb.ts b/electron/src/generated/rag_engine_pb.ts deleted file mode 100644 index d138dcb..0000000 --- a/electron/src/generated/rag_engine_pb.ts +++ /dev/null @@ -1,389 +0,0 @@ -// @generated by protoc-gen-es v2.2.2 with parameter "target=ts" -// @generated from file rag_engine.proto (package fi.rag.v1, syntax proto3) -/* eslint-disable */ - -import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1"; -import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1"; -import { file_google_protobuf_empty, file_google_protobuf_struct } from "@bufbuild/protobuf/wkt"; -import type { Error } from "./common_pb"; -import { file_common } from "./common_pb"; -import type { JsonObject, Message } from "@bufbuild/protobuf"; - -/** - * Describes the file rag_engine.proto. - */ -export const file_rag_engine: GenFile = /*@__PURE__*/ - fileDesc("ChByYWdfZW5naW5lLnByb3RvEglmaS5yYWcudjEiewoUU3RvcmVEb2N1bWVudFJlcXVlc3QSEwoLZG9jdW1lbnRfaWQYASABKAkSDwoHY29udGVudBgCIAEoCRIpCghtZXRhZGF0YRgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSEgoKc291cmNlX3VybBgEIAEoCSJ4ChVTdG9yZURvY3VtZW50UmVzcG9uc2USEwoLZG9jdW1lbnRfaWQYASABKAkSDwoHc3VjY2VzcxgCIAEoCBIVCg1jaHVua3Nfc3RvcmVkGAMgASgFEiIKBWVycm9yGAQgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIl8KD1JldHJpZXZlUmVxdWVzdBINCgVxdWVyeRgBIAEoCRITCgttYXhfcmVzdWx0cxgCIAEoBRIoCgdmaWx0ZXJzGAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdCJfChBSZXRyaWV2ZVJlc3BvbnNlEicKBmNodW5rcxgBIAMoCzIXLmZpLnJhZy52MS5Db250ZXh0Q2h1bmsSIgoFZXJyb3IYAiABKAsyEy5maS5jb21tb24udjEuRXJyb3IicwoMQ29udGV4dENodW5rEg8KB2NvbnRlbnQYASABKAkSFwoPcmVsZXZhbmNlX3Njb3JlGAIgASgBEikKCG1ldGFkYXRhGAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIOCgZzb3VyY2UYBCABKAkiIAoQRW1iZWRkaW5nUmVxdWVzdBIMCgR0ZXh0GAEgASgJIkoKEUVtYmVkZGluZ1Jlc3BvbnNlEhEKCWVtYmVkZGluZxgBIAMoAhIiCgVlcnJvchgCIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvciJXCg1TZWFyY2hSZXF1ZXN0Eg0KBXF1ZXJ5GAEgASgJEg0KBWxpbWl0GAIgASgFEigKB2ZpbHRlcnMYAyABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Il4KDlNlYXJjaFJlc3BvbnNlEigKB3Jlc3VsdHMYASADKAsyFy5maS5yYWcudjEuU2VhcmNoUmVzdWx0EiIKBWVycm9yGAIgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIm4KDFNlYXJjaFJlc3VsdBITCgtkb2N1bWVudF9pZBgBIAEoCRIPCgdjb250ZW50GAIgASgJEg0KBXNjb3JlGAMgASgBEikKCG1ldGFkYXRhGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdDLCAgoJUkFHRW5naW5lElIKDVN0b3JlRG9jdW1lbnQSHy5maS5yYWcudjEuU3RvcmVEb2N1bWVudFJlcXVlc3QaIC5maS5yYWcudjEuU3RvcmVEb2N1bWVudFJlc3BvbnNlEkoKD1JldHJpZXZlQ29udGV4dBIaLmZpLnJhZy52MS5SZXRyaWV2ZVJlcXVlc3QaGy5maS5yYWcudjEuUmV0cmlldmVSZXNwb25zZRJOChFHZW5lcmF0ZUVtYmVkZGluZxIbLmZpLnJhZy52MS5FbWJlZGRpbmdSZXF1ZXN0GhwuZmkucmFnLnYxLkVtYmVkZGluZ1Jlc3BvbnNlEkUKDlNlbWFudGljU2VhcmNoEhguZmkucmFnLnYxLlNlYXJjaFJlcXVlc3QaGS5maS5yYWcudjEuU2VhcmNoUmVzcG9uc2VCogEKDWNvbS5maS5yYWcudjFCDlJhZ0VuZ2luZVByb3RvUAFaO2dpdGh1Yi5jb20vRmlyZWxpZ2h0LUlubm92YXRpb25zL0ZpQXBwbHkvcHJvdG8vcmFnL3YxO3JhZ3YxogIDRlJYqgIJRmkuUmFnLlYxygIJRmlcUmFnXFYx4gIVRmlcUmFnXFYxXEdQQk1ldGFkYXRh6gILRmk6OlJhZzo6VjFiBnByb3RvMw", [file_google_protobuf_struct, file_google_protobuf_empty, file_common]); - -/** - * @generated from message fi.rag.v1.StoreDocumentRequest - */ -export type StoreDocumentRequest = Message<"fi.rag.v1.StoreDocumentRequest"> & { - /** - * Unique document identifier - * - * @generated from field: string document_id = 1; - */ - documentId: string; - - /** - * Document content to store - * - * @generated from field: string content = 2; - */ - content: string; - - /** - * Additional metadata (title, author, date, etc.) - * - * @generated from field: google.protobuf.Struct metadata = 3; - */ - metadata?: JsonObject; - - /** - * Source URL if document is from web - * - * @generated from field: string source_url = 4; - */ - sourceUrl: string; -}; - -/** - * Describes the message fi.rag.v1.StoreDocumentRequest. - * Use `create(StoreDocumentRequestSchema)` to create a new message. - */ -export const StoreDocumentRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 0); - -/** - * @generated from message fi.rag.v1.StoreDocumentResponse - */ -export type StoreDocumentResponse = Message<"fi.rag.v1.StoreDocumentResponse"> & { - /** - * Document identifier - * - * @generated from field: string document_id = 1; - */ - documentId: string; - - /** - * Whether storage was successful - * - * @generated from field: bool success = 2; - */ - success: boolean; - - /** - * Number of chunks created and stored - * - * @generated from field: int32 chunks_stored = 3; - */ - chunksStored: number; - - /** - * Error details if storage failed - * - * @generated from field: fi.common.v1.Error error = 4; - */ - error?: Error; -}; - -/** - * Describes the message fi.rag.v1.StoreDocumentResponse. - * Use `create(StoreDocumentResponseSchema)` to create a new message. - */ -export const StoreDocumentResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 1); - -/** - * @generated from message fi.rag.v1.RetrieveRequest - */ -export type RetrieveRequest = Message<"fi.rag.v1.RetrieveRequest"> & { - /** - * Query text to find relevant context for - * - * @generated from field: string query = 1; - */ - query: string; - - /** - * Maximum number of results to return - * - * @generated from field: int32 max_results = 2; - */ - maxResults: number; - - /** - * Optional filters (source, date range, etc.) - * - * @generated from field: google.protobuf.Struct filters = 3; - */ - filters?: JsonObject; -}; - -/** - * Describes the message fi.rag.v1.RetrieveRequest. - * Use `create(RetrieveRequestSchema)` to create a new message. - */ -export const RetrieveRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 2); - -/** - * @generated from message fi.rag.v1.RetrieveResponse - */ -export type RetrieveResponse = Message<"fi.rag.v1.RetrieveResponse"> & { - /** - * Relevant context chunks ranked by similarity - * - * @generated from field: repeated fi.rag.v1.ContextChunk chunks = 1; - */ - chunks: ContextChunk[]; - - /** - * Error details if retrieval failed - * - * @generated from field: fi.common.v1.Error error = 2; - */ - error?: Error; -}; - -/** - * Describes the message fi.rag.v1.RetrieveResponse. - * Use `create(RetrieveResponseSchema)` to create a new message. - */ -export const RetrieveResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 3); - -/** - * @generated from message fi.rag.v1.ContextChunk - */ -export type ContextChunk = Message<"fi.rag.v1.ContextChunk"> & { - /** - * Chunk content - * - * @generated from field: string content = 1; - */ - content: string; - - /** - * Relevance score (0.0 to 1.0) - * - * @generated from field: double relevance_score = 2; - */ - relevanceScore: number; - - /** - * Chunk metadata - * - * @generated from field: google.protobuf.Struct metadata = 3; - */ - metadata?: JsonObject; - - /** - * Source document or URL - * - * @generated from field: string source = 4; - */ - source: string; -}; - -/** - * Describes the message fi.rag.v1.ContextChunk. - * Use `create(ContextChunkSchema)` to create a new message. - */ -export const ContextChunkSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 4); - -/** - * @generated from message fi.rag.v1.EmbeddingRequest - */ -export type EmbeddingRequest = Message<"fi.rag.v1.EmbeddingRequest"> & { - /** - * Text to generate embedding for - * - * @generated from field: string text = 1; - */ - text: string; -}; - -/** - * Describes the message fi.rag.v1.EmbeddingRequest. - * Use `create(EmbeddingRequestSchema)` to create a new message. - */ -export const EmbeddingRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 5); - -/** - * @generated from message fi.rag.v1.EmbeddingResponse - */ -export type EmbeddingResponse = Message<"fi.rag.v1.EmbeddingResponse"> & { - /** - * Embedding vector - * - * @generated from field: repeated float embedding = 1; - */ - embedding: number[]; - - /** - * Error details if embedding generation failed - * - * @generated from field: fi.common.v1.Error error = 2; - */ - error?: Error; -}; - -/** - * Describes the message fi.rag.v1.EmbeddingResponse. - * Use `create(EmbeddingResponseSchema)` to create a new message. - */ -export const EmbeddingResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 6); - -/** - * @generated from message fi.rag.v1.SearchRequest - */ -export type SearchRequest = Message<"fi.rag.v1.SearchRequest"> & { - /** - * Search query - * - * @generated from field: string query = 1; - */ - query: string; - - /** - * Maximum number of results - * - * @generated from field: int32 limit = 2; - */ - limit: number; - - /** - * Optional filters (source, date, etc.) - * - * @generated from field: google.protobuf.Struct filters = 3; - */ - filters?: JsonObject; -}; - -/** - * Describes the message fi.rag.v1.SearchRequest. - * Use `create(SearchRequestSchema)` to create a new message. - */ -export const SearchRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 7); - -/** - * @generated from message fi.rag.v1.SearchResponse - */ -export type SearchResponse = Message<"fi.rag.v1.SearchResponse"> & { - /** - * Search results ranked by relevance - * - * @generated from field: repeated fi.rag.v1.SearchResult results = 1; - */ - results: SearchResult[]; - - /** - * Error details if search failed - * - * @generated from field: fi.common.v1.Error error = 2; - */ - error?: Error; -}; - -/** - * Describes the message fi.rag.v1.SearchResponse. - * Use `create(SearchResponseSchema)` to create a new message. - */ -export const SearchResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 8); - -/** - * @generated from message fi.rag.v1.SearchResult - */ -export type SearchResult = Message<"fi.rag.v1.SearchResult"> & { - /** - * Document identifier - * - * @generated from field: string document_id = 1; - */ - documentId: string; - - /** - * Matching content snippet - * - * @generated from field: string content = 2; - */ - content: string; - - /** - * Relevance score (0.0 to 1.0) - * - * @generated from field: double score = 3; - */ - score: number; - - /** - * Document metadata - * - * @generated from field: google.protobuf.Struct metadata = 4; - */ - metadata?: JsonObject; -}; - -/** - * Describes the message fi.rag.v1.SearchResult. - * Use `create(SearchResultSchema)` to create a new message. - */ -export const SearchResultSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_rag_engine, 9); - -/** - * RAG Engine - Retrieval-Augmented Generation processing - * - * @generated from service fi.rag.v1.RAGEngine - */ -export const RAGEngine: GenService<{ - /** - * Store document or webpage content with embeddings - * - * @generated from rpc fi.rag.v1.RAGEngine.StoreDocument - */ - storeDocument: { - methodKind: "unary"; - input: typeof StoreDocumentRequestSchema; - output: typeof StoreDocumentResponseSchema; - }, - /** - * Retrieve relevant context for a query using vector similarity - * - * @generated from rpc fi.rag.v1.RAGEngine.RetrieveContext - */ - retrieveContext: { - methodKind: "unary"; - input: typeof RetrieveRequestSchema; - output: typeof RetrieveResponseSchema; - }, - /** - * Generate embeddings for text - * - * @generated from rpc fi.rag.v1.RAGEngine.GenerateEmbedding - */ - generateEmbedding: { - methodKind: "unary"; - input: typeof EmbeddingRequestSchema; - output: typeof EmbeddingResponseSchema; - }, - /** - * Perform semantic search across stored documents - * - * @generated from rpc fi.rag.v1.RAGEngine.SemanticSearch - */ - semanticSearch: { - methodKind: "unary"; - input: typeof SearchRequestSchema; - output: typeof SearchResponseSchema; - }, -}> = /*@__PURE__*/ - serviceDesc(file_rag_engine, 0); - diff --git a/electron/src/renderer/src/App.tsx b/electron/src/renderer/src/App.tsx deleted file mode 100644 index 870378c..0000000 --- a/electron/src/renderer/src/App.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useState } from 'react' - -export default function App() { - const [count, setCount] = useState(0) - - return ( -
-
-

โšก FiApply

-

Electron + Vite + React + TypeScript

- -
- -

- Edit src/renderer/src/App.tsx and save to test HMR -

-
- -

- Click on the Electron, Vite, and React logos to learn more -

-
-
- ) -} \ No newline at end of file diff --git a/electron/src/renderer/src/style.css b/electron/src/renderer/src/style.css deleted file mode 100644 index 53fe577..0000000 --- a/electron/src/renderer/src/style.css +++ /dev/null @@ -1,104 +0,0 @@ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -:root { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -body { - margin: 0; - display: flex; - min-width: 320px; - min-height: 100vh; -} - -#root { - width: 100%; - min-height: 100vh; -} - -.app-container { - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - padding: 2rem; -} - -.content { - text-align: center; - max-width: 600px; -} - -h1 { - font-size: 3.5rem; - margin-bottom: 1rem; - font-weight: 700; -} - -.subtitle { - font-size: 1.25rem; - margin-bottom: 2rem; - opacity: 0.9; -} - -.card { - background: rgba(255, 255, 255, 0.1); - backdrop-filter: blur(10px); - border-radius: 12px; - padding: 2rem; - margin: 2rem 0; - border: 1px solid rgba(255, 255, 255, 0.2); -} - -button { - background: rgba(255, 255, 255, 0.9); - color: #667eea; - border: none; - padding: 0.75rem 2rem; - font-size: 1.125rem; - font-weight: 600; - border-radius: 8px; - cursor: pointer; - transition: all 0.3s ease; - font-family: inherit; -} - -button:hover { - background: white; - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); -} - -button:active { - transform: translateY(0); -} - -.info { - margin-top: 1.5rem; - font-size: 0.875rem; - opacity: 0.8; - line-height: 1.6; -} - -code { - background: rgba(255, 255, 255, 0.2); - padding: 0.25rem 0.5rem; - border-radius: 4px; - font-family: 'Courier New', monospace; -} - -.footer { - font-size: 0.875rem; - opacity: 0.7; - margin-top: 2rem; -} diff --git a/electron/src/services/LoggerService.ts b/electron/src/services/LoggerService.ts deleted file mode 100644 index a91c49e..0000000 --- a/electron/src/services/LoggerService.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Logger, type ILogObj } from "tslog"; - -/* - > https://tslog.js.org/#/ - - ? levels: 0 - silly, 1 - debug, 2 - trace, 3 - info, 4 - warn, 5 - error, 6 - fatal - - ? Log messages at different levels - log.silly("message"); - ... - log.fatal(new Error("Pretty Error with stacktrace.")); - - ? Log with metadata - log.info("User logged in", { userId: "abc123", role: "admin" }); - - ? Create custom logger with a pretty log template for custom formatting - const customLogger: Logger = new Logger({ - minLevel: 1, - name: "CustomLogger", - type: "pretty", - prettyLogTemplate: "{{logLevelName}} [{{name}}]: {{message}}" - }); - - ? Conditional logging based on environment (eg show debug logs only in development) - if (import.meta.env.VITE_LEVEL != "development") { - log.debug("Debug logs are only visible in development"); - } -*/ - -//* Master logger to spawn all sub-loggers -export const MasterLog: Logger = new Logger({ - //minLevel: 0, ? levels: 0 - silly, 1 - debug, 2 - trace, 3 - info, 4 - warn, 5 - error, 6 - fatal - name: "Frontend", - type: "pretty", - prettyLogTemplate: "{{logLevelName}} [{{name}}] [{{fileNameWithLine}}]:\t", - prettyErrorTemplate: "\n{{errorName}} {{errorMessage}}\nerror stack:\n{{errorStack}}\n", - prettyErrorStackTemplate: " โ€ข {{fileName}}\t{{method}}\n\t{{filePathWithLine}}\n", - stylePrettyLogs: true, - prettyLogStyles: { - logLevelName: { - "*": ["bold", "black", "bgWhiteBright", "dim"], - SILLY: ["bold", "white"], - TRACE: ["bold", "whiteBright"], - DEBUG: ["bold", "green"], - INFO: ["bold", "blue"], - WARN: ["bold", "yellow"], - ERROR: ["bold", "red"], - FATAL: ["bold", "redBright"], - }, - dateIsoStr: "white", - filePathWithLine: "white", - name: ["white", "bold"], - nameWithDelimiterPrefix: ["white", "bold"], - nameWithDelimiterSuffix: ["white", "bold"], - errorName: ["bold", "bgRedBright", "whiteBright"], - fileName: ["yellow"], - } -}); \ No newline at end of file diff --git a/electron/src/services/RPCService.ts b/electron/src/services/RPCService.ts deleted file mode 100644 index d5cda3e..0000000 --- a/electron/src/services/RPCService.ts +++ /dev/null @@ -1,48 +0,0 @@ -// src/services/RPCService.ts -import { createConnectTransport } from "@connectrpc/connect-web"; -import { createClient } from "@connectrpc/connect"; - -import { Gateway } from "@/generated/api_gateway_connect"; - -import { MasterLog } from "./LoggerService"; - - -const Log = MasterLog.getSubLogger({ name: "RPCService" }); - -const BASE_URL = import.meta.env.VITE_GRPC_BASE_URL || "http://localhost:9090"; -const transport = createConnectTransport({ baseUrl: BASE_URL }); - -interface ClientCache { - gateway?: ReturnType; -} - -const clientCache: ClientCache = {}; - -/** - * gRPC service class to manage client connections - */ -export class RPCService { - /** - * @returns The Gateway client - */ - static getGateway() { - if (!clientCache.gateway) { - // @ts-expect-error - Generated service descriptor type mismatch with createClient - clientCache.gateway = createClient(Gateway, transport); - Log.debug('Created new gRPC client for Gateway'); - } - return clientCache.gateway; - } - - /** - * Reset all clients - */ - static resetClients() { - Object.keys(clientCache).forEach(key => { - delete clientCache[key as keyof ClientCache]; - }); - Log.info('Reset all gRPC clients'); - } -} - -export default RPCService; \ No newline at end of file diff --git a/electron/src/services/UpdateSignalManager.ts b/electron/src/services/UpdateSignalManager.ts deleted file mode 100644 index 59bec07..0000000 --- a/electron/src/services/UpdateSignalManager.ts +++ /dev/null @@ -1,225 +0,0 @@ -// src/services/UpdateSignalManager.ts -import { ConnectionState, WEBSOCKET_URL } from '@global/updateSignal'; - -import { MasterLog } from '@services/LoggerService'; - -// Currently triggers update when "UPDATE" received via websocket - - -const Log = MasterLog.getSubLogger({ name: "UpdateSignal" }) - -export class UpdateSignalManager { - private static instance: UpdateSignalManager | null = null; - private socket: WebSocket | null = null; - private listeners: Set<() => void> = new Set(); - private connectionState: ConnectionState = ConnectionState.DISCONNECTED; - private stateChangeCallbacks: Set<(state: ConnectionState) => void> = new Set(); - private reconnectTimer: ReturnType | null = null; - private reconnectAttempts = 0; - private readonly MAX_RECONNECT_ATTEMPTS = 5; - private readonly url: string; - - private constructor(url: string) { - this.url = url; - } - - /** - * Get singleton of manager - */ - public static getInstance(url: string = WEBSOCKET_URL): UpdateSignalManager { - if (!UpdateSignalManager.instance) { - UpdateSignalManager.instance = new UpdateSignalManager(url); - } - return UpdateSignalManager.instance; - } - - /** - * Connect to WebSocket - */ - public connect(): void { - if (this.socket?.readyState === WebSocket.OPEN) return; - - this.setConnectionState(ConnectionState.CONNECTING); - - try { - this.socket = new WebSocket(this.url); - - this.socket.onopen = this.handleOpen.bind(this); - this.socket.onmessage = this.handleMessage.bind(this); - this.socket.onclose = this.handleClose.bind(this); - this.socket.onerror = this.handleError.bind(this); - } catch (error) { - Log.error('Failed to create WebSocket connection', { Error: error }); - this.setConnectionState(ConnectionState.ERROR); - this.scheduleReconnect(); - } - } - - /** - * Disconnect from WebSocket - */ - public disconnect(): void { - if (this.socket) { - this.socket.close(); - this.socket = null; - } - - if (this.reconnectTimer) { - clearTimeout(this.reconnectTimer); - this.reconnectTimer = null; - } - - this.setConnectionState(ConnectionState.DISCONNECTED); - } - - /** - * Subs to update signals - * @returns Unsub function - */ - public subscribe(callback: () => void): () => void { - this.listeners.add(callback); - - // Connect if not already - if (this.connectionState !== ConnectionState.CONNECTED && - this.connectionState !== ConnectionState.CONNECTING) { - this.connect(); - } - - // Return unsubscribe function - return () => { - this.unsubscribe(callback); - }; - } - - /** - * Unsubs from update signals - */ - public unsubscribe(callback: () => void): void { - this.listeners.delete(callback); - - if (this.listeners.size === 0) { - this.disconnect(); - } - } - - /** - * Subs to connection-state changes - * @returns Unsubscribe function - */ - public onConnectionStateChange(callback: (state: ConnectionState) => void): () => void { - this.stateChangeCallbacks.add(callback); - - // Call immediately with state - callback(this.connectionState); - - // Return unsub function - return () => { - this.stateChangeCallbacks.delete(callback); - }; - } - - /** - * Get connection state - */ - public getConnectionState(): ConnectionState { - return this.connectionState; - } - - /** - * Handle WebSocket opened - */ - private handleOpen(): void { - Log.info('WebSocket connection established', { URL: this.url }); - this.reconnectAttempts = 0; - this.setConnectionState(ConnectionState.CONNECTED); - } - - /** - * Handle incoming WebSocket messages - */ - private handleMessage(event: MessageEvent): void { - try { - if (event.data === 'UPDATE') { - Log.info('Received UPDATE signal from WebSocket'); - this.notifyListeners(); - } - } catch (error) { - Log.error('Error processing WebSocket message', { Error: error }); - } - } - - /** - * Handle WebSocket closed - */ - private handleClose(event: CloseEvent): void { - Log.info('WebSocket connection closed', { Code: event.code, Reason: event.reason }); - this.setConnectionState(ConnectionState.DISCONNECTED); - this.scheduleReconnect(); - } - - /** - * Handle WebSocket errors - */ - private handleError(event: Event): void { - Log.error('WebSocket error', { Event: event }); - this.setConnectionState(ConnectionState.ERROR); - } - - /** - * Schedule reconnection (exponential backoff) - */ - private scheduleReconnect(): void { - if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) { - Log.error('Maximum reconnection attempts reached'); - return; - } - - if (this.listeners.size === 0) { - Log.info('No active listeners, skipping reconnection'); - return; - } - - const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000); - this.reconnectAttempts++; - - Log.info('Scheduling reconnection attempt', { - Attempt: this.reconnectAttempts, - MaxAttempts: this.MAX_RECONNECT_ATTEMPTS, - DelayMs: delay - }); - - this.reconnectTimer = setTimeout(() => { - this.connect(); - }, delay); - } - - /** - * Update connection state & notify listeners - */ - private setConnectionState(state: ConnectionState): void { - if (this.connectionState === state) return; - - this.connectionState = state; - this.stateChangeCallbacks.forEach(callback => { - try { - callback(state); - } catch (error) { - Log.error('Error in connection state change callback', { Error: error }); - } - }); - } - - /** - * Notify all listeners if update - */ - private notifyListeners(): void { - this.listeners.forEach(listener => { - try { - listener(); - } catch (error) { - Log.error('Error in update listener', { Error: error }); - // Consider removing problematic listeners after multiple failures - } - }); - } -} \ No newline at end of file diff --git a/electron/tsconfig.json b/electron/tsconfig.json deleted file mode 100644 index 6983ba4..0000000 --- a/electron/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.node.json" }, - { "path": "./tsconfig.renderer.json" } - ] -} diff --git a/electron/tsconfig.node.json b/electron/tsconfig.node.json deleted file mode 100644 index fa62b41..0000000 --- a/electron/tsconfig.node.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "target": "ES2020", - "module": "ESNext", - "lib": ["ES2020"], - "moduleResolution": "bundler", - "resolveJsonModule": true, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "skipLibCheck": true, - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "baseUrl": ".", - "paths": { - "@/*": ["src/*"], - "@services/*": ["src/services/*"], - "@global/*": ["src/types/global/*"], - "@renderer/*": ["src/renderer/src/*"], - "@hooks/*": ["src/renderer/src/hooks/*"], - "@main/*": ["src/main/*"], - "@preload/*": ["src/preload/*"] - } - }, - "include": ["src/main/**/*"], - "exclude": ["node_modules", "out"] -} diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf3..32752c7 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,24 +1,7 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - node_modules dist -dist-ssr +out *.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? +**/.DS_Store +*.tsbuildinfo +.vite diff --git a/frontend/Dockerfile b/frontend/Dockerfile index e48ebb6..e3b24ec 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,11 +1,11 @@ -# Frontend Dockerfile +# Frontend Dockerfile (Electron + Vite + React) # Multi-stage build for development and production FROM node:20-alpine as base WORKDIR /app -# Development stage +# Development stage - runs electron-vite dev server FROM base as development # Install dependencies @@ -15,30 +15,43 @@ RUN npm ci # Copy application code COPY . . -# Expose dev server port -EXPOSE 3000 +# Expose dev server port (for the renderer/web interface) +EXPOSE 5173 -# Run dev server -CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] +# Run electron-vite dev server (renderer only for web access) +CMD ["npm", "run", "dev"] -# Build stage +# Build stage - builds the electron app FROM base as build COPY package*.json ./ RUN npm ci COPY . . + +# Build the electron application RUN npm run build -# Production stage (nginx) +# The built files will be in the /app/out directory +# These can be copied to a host volume for distribution + +# Production stage - serve built renderer files with nginx (web access only) FROM nginx:alpine as production -# Copy built files -COPY --from=build /app/dist /usr/share/nginx/html +# Copy built renderer files +COPY --from=build /app/out/renderer /usr/share/nginx/html -# Copy nginx config -COPY nginx.conf /etc/nginx/conf.d/default.conf +# Create a minimal nginx config for SPA +RUN echo 'server { \ + listen 80; \ + location / { \ + root /usr/share/nginx/html; \ + try_files $uri $uri/ /index.html; \ + add_header Cache-Control "no-cache"; \ + } \ +}' > /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] + diff --git a/frontend/README.md b/frontend/README.md index 9cee4bb..c1b382b 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,187 +1,404 @@ -# Fi Frontend +# FiApply Electron Application -React TypeScript PWA for the Fi job and scholarship application automation system. - -## Tech Stack - -- **Framework**: React 18 + TypeScript -- **Build Tool**: Vite -- **UI Library**: ShadCN UI -- **Styling**: Tailwind CSS -- **State Management**: Redux Toolkit -- **API Client**: Connect RPC (gRPC-Web) -- **Icons**: Lucide React +Electron desktop application built with Vite, React, and TypeScript. ## Project Structure ``` -frontend/ +electron/ โ”œโ”€โ”€ src/ -โ”‚ โ”œโ”€โ”€ api/ # Connect RPC client configuration -โ”‚ โ”‚ โ”œโ”€โ”€ client.ts # API client setup -โ”‚ โ”‚ โ””โ”€โ”€ hooks.ts # React hooks for API calls -โ”‚ โ”œโ”€โ”€ components/ -โ”‚ โ”‚ โ””โ”€โ”€ ui/ # ShadCN UI components -โ”‚ โ”œโ”€โ”€ features/ # Feature-based modules -โ”‚ โ”‚ โ””โ”€โ”€ health/ # Health check feature -โ”‚ โ”œโ”€โ”€ lib/ # Utility functions -โ”‚ โ”œโ”€โ”€ store/ # Redux store configuration -โ”‚ โ”œโ”€โ”€ App.tsx # Main app component -โ”‚ โ”œโ”€โ”€ main.tsx # App entry point -โ”‚ โ””โ”€โ”€ index.css # Global styles + Tailwind -โ”œโ”€โ”€ public/ # Static assets +โ”‚ โ”œโ”€โ”€ main/ # Electron main process (Node.js) +โ”‚ โ”‚ โ””โ”€โ”€ index.ts +โ”‚ โ”œโ”€โ”€ preload/ # Preload scripts (bridge between main/renderer) +โ”‚ โ”‚ โ”œโ”€โ”€ index.ts +โ”‚ โ”‚ โ””โ”€โ”€ index.d.ts +โ”‚ โ”œโ”€โ”€ renderer/ # Frontend React application +โ”‚ โ”‚ โ”œโ”€โ”€ index.html +โ”‚ โ”‚ โ””โ”€โ”€ src/ +โ”‚ โ”‚ โ”œโ”€โ”€ main.tsx # React entry point +โ”‚ โ”‚ โ”œโ”€โ”€ App.tsx # Main React component +โ”‚ โ”‚ โ”œโ”€โ”€ style.css +โ”‚ โ”‚ โ””โ”€โ”€ hooks/ # Custom React hooks +โ”‚ โ”‚ โ”œโ”€โ”€ data/ # Data fetching hooks (useRPC, useUpdateSignal) +โ”‚ โ”‚ โ”œโ”€โ”€ state/ # State management hooks +โ”‚ โ”‚ โ”œโ”€โ”€ ui/ # UI-related hooks +โ”‚ โ”‚ โ””โ”€โ”€ utils/ # Utility hooks (useDebounce, etc.) +โ”‚ โ”œโ”€โ”€ services/ # Service classes (shared logic) +โ”‚ โ”‚ โ”œโ”€โ”€ LoggerService.ts +โ”‚ โ”‚ โ”œโ”€โ”€ RPCService.ts +โ”‚ โ”‚ โ””โ”€โ”€ UpdateSignalManager.ts +โ”‚ โ”œโ”€โ”€ store/ # Redux/state management +โ”‚ โ”‚ โ”œโ”€โ”€ index.ts +โ”‚ โ”‚ โ””โ”€โ”€ hooks.ts +โ”‚ โ”œโ”€โ”€ types/ # TypeScript type definitions +โ”‚ โ”‚ โ”œโ”€โ”€ global/ # Global types available everywhere +โ”‚ โ”‚ โ”œโ”€โ”€ node/ # Types for main/preload processes +โ”‚ โ”‚ โ””โ”€โ”€ renderer/ # Types for renderer process +โ”‚ โ””โ”€โ”€ generated/ # Auto-generated Protobuf files +โ”‚ โ””โ”€โ”€ *_pb.ts +โ”œโ”€โ”€ electron.vite.config.ts # Vite configuration for all processes +โ”œโ”€โ”€ tsconfig.json # Root TypeScript config (for build tools) +โ”œโ”€โ”€ tsconfig.node.json # TypeScript config for main/preload +โ”œโ”€โ”€ tsconfig.renderer.json # TypeScript config for renderer โ””โ”€โ”€ package.json ``` -## Setup +## Quick Start -### Prerequisites - -- Node.js 18+ -- npm or yarn - -### Installation +### Install Dependencies ```bash -# Install dependencies npm install +``` -# Copy environment variables -cp .env.example .env +### Development -# Generate proto code (from project root) -cd .. -buf generate +Start development server with hot reload: -# Start development server -cd frontend +```bash npm run dev ``` -The app will run on `http://localhost:3000` +This will: +- Start Vite dev server for the renderer (React) +- Watch and compile main/preload processes +- Launch Electron with DevTools +- Enable hot module replacement -## Development +### Build -### Available Scripts +Create production build: ```bash -# Start dev server -npm run dev - -# Build for production npm run build +``` -# Preview production build -npm run preview +Output will be in the `out/` directory: +- `out/main/` - Main process bundle +- `out/preload/` - Preload scripts bundle +- `out/renderer/` - Renderer (React) bundle + +### Preview Production Build -# Lint code -npm run lint +Test the production build locally: + +```bash +npm run preview +# or +npm start ``` -### Adding ShadCN Components +### Type Checking -To add more ShadCN components: +Check TypeScript types without building: ```bash -npx shadcn-ui@latest add [component-name] +npm run typecheck # Check all processes +npm run typecheck:node # Check main & preload only +npm run typecheck:web # Check renderer only ``` -Example: -```bash -npx shadcn-ui@latest add button -npx shadcn-ui@latest add dialog -npx shadcn-ui@latest add input +## NPM Scripts Reference + +| Command | Description | +|---------|-------------| +| `npm run dev` | Start development mode with hot reload | +| `npm run build` | Build for production | +| `npm run preview` | Run production build locally | +| `npm start` | Alias for `preview` | +| `npm run typecheck` | Type check all TypeScript files | +| `npm run typecheck:node` | Type check main & preload processes | +| `npm run typecheck:web` | Type check renderer process | + +## Tech Stack + +- **Electron** 28.0.0 - Desktop application framework +- **Vite** 5.4.11 - Build tool and dev server +- **React** 18.3.1 - UI library +- **TypeScript** 5.8.3 - Type-safe JavaScript +- **electron-vite** 2.3.0 - Vite integration for Electron + +## Development Notes + +### Process Architecture + +- **Main Process**: Controls app lifecycle, creates windows, manages system-level operations +- **Preload Scripts**: Secure bridge between main and renderer with context isolation +- **Renderer Process**: React frontend running in Chromium + +### Hot Module Replacement + +- **Renderer changes**: Instant HMR with state preservation +- **Main/Preload changes**: Automatic Electron restart + +### Path Aliases + +Renderer code can use `@renderer/*` alias: + +```typescript +import { Component } from '@renderer/components/Component' ``` -## Environment Variables +### Accessing Electron APIs in Renderer -Create a `.env` file: +Use the exposed APIs via preload: -```bash -# API Configuration -VITE_API_BASE_URL=http://localhost:50051 +```typescript +// Access Electron APIs +window.electron.process.platform + +// Access custom APIs +window.api.yourCustomMethod() +``` + +## Common Tasks + +### Adding TypeScript Types + +Types are organized by their scope and usage: + +#### Global Types (Used Everywhere) +**Location**: `src/types/global/` + +Use for types shared across all processes (main, preload, renderer): +```typescript +// src/types/global/app.ts +export interface AppConfig { + name: string; + version: string; +} +``` + +Register in `tsconfig.node.json` and `tsconfig.renderer.json`: +```json +{ + "compilerOptions": { + "types": ["node", "src/types/global"] + } +} +``` + +#### Node/Main Process Types +**Location**: `src/types/node/` + +Use for types specific to main process and preload scripts: +```typescript +// src/types/node/ipc.ts +export interface IpcChannels { + 'file:open': string; + 'app:quit': void; +} +``` + +Referenced in `tsconfig.node.json`: +```json +{ + "compilerOptions": { + "types": ["node", "src/types/global", "src/types/node"] + } +} +``` -# Environment -VITE_ENV=development +#### Renderer Process Types +**Location**: `src/types/renderer/` + +Use for types specific to React/UI code: +```typescript +// src/types/renderer/components.ts +export interface ButtonProps { + variant: 'primary' | 'secondary'; + onClick: () => void; +} ``` -## State Management +### Adding React Hooks -This project uses Redux Toolkit with a feature-based structure: +Custom hooks go in `src/renderer/src/hooks/`, organized by category: + +#### Data Hooks (`hooks/data/`) +For data fetching, API calls, and real-time updates: ```typescript -// Using typed hooks -import { useAppDispatch, useAppSelector } from '@/store/hooks'; +// src/renderer/src/hooks/data/useUser.ts +import { useState, useEffect } from 'react'; -function MyComponent() { - const dispatch = useAppDispatch(); - const data = useAppSelector((state) => state.myFeature); +export function useUser(userId: string) { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // Fetch user data + fetchUser(userId).then(setUser).finally(() => setLoading(false)); + }, [userId]); - // Use dispatch and selector as normal + return { user, loading }; } ``` -## API Communication +**Examples**: `useRPC.ts`, `useUpdateSignal.ts` -The frontend uses Connect RPC for type-safe gRPC communication: +#### State Hooks (`hooks/state/`) +For Redux/Zustand integration or complex state management: ```typescript -import { createApiClient } from '@/api/client'; -import { MyService } from '@/generated/...'; +// src/renderer/src/hooks/state/useAppState.ts +import { useSelector, useDispatch } from 'react-redux'; -const client = createApiClient(MyService); -const response = await client.myMethod({ ... }); +export function useAppState() { + const state = useSelector((state) => state.app); + const dispatch = useDispatch(); + + return { state, dispatch }; +} ``` -## Styling +#### UI Hooks (`hooks/ui/`) +For UI behavior, animations, and browser APIs: -This project uses Tailwind CSS with ShadCN UI: +```typescript +// src/renderer/src/hooks/ui/useWindowSize.ts +import { useState, useEffect } from 'react'; + +export function useWindowSize() { + const [size, setSize] = useState({ + width: window.innerWidth, + height: window.innerHeight + }); + + useEffect(() => { + const handleResize = () => setSize({ + width: window.innerWidth, + height: window.innerHeight + }); + + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + return size; +} +``` + +#### Utils Hooks (`hooks/utils/`) +For utility functions and helpers: + +```typescript +// src/renderer/src/hooks/utils/useDebounce.ts +import { useState, useEffect } from 'react'; + +export function useDebounce(value: T, delay: number): T { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = setTimeout(() => setDebouncedValue(value), delay); + return () => clearTimeout(handler); + }, [value, delay]); + + return debouncedValue; +} +``` -- **Tailwind utilities**: Use for spacing, layout, colors -- **ShadCN components**: Pre-built, accessible components -- **CSS variables**: Defined in `index.css` for theming +**Examples**: `useDebounce.ts` -### Dark Mode +#### Re-export Hooks +Create an `index.ts` in each category to re-export hooks: -Dark mode is supported via CSS variables. Toggle with: +```typescript +// src/renderer/src/hooks/data/index.ts +export * from './useRPC'; +export * from './useUpdateSignal'; +export * from './useUser'; +``` +Then import from the category: ```typescript -document.documentElement.classList.toggle('dark'); +import { useRPC, useUpdateSignal } from '@renderer/hooks/data'; ``` -## Building for Production +### Adding React Components + +Create components in `src/renderer/src/`: + +```tsx +// src/renderer/src/components/MyComponent.tsx +interface MyComponentProps { + title: string +} + +function MyComponent({ title }: MyComponentProps) { + return

{title}

+} + +export default MyComponent +``` + +### Adding Dependencies ```bash -npm run build +# Runtime dependencies (e.g., React libraries) +npm install package-name + +# Development dependencies (e.g., types, build tools) +npm install -D package-name ``` -The optimized build will be in `dist/` directory. +### Configuring Vite + +Edit `electron.vite.config.ts` to customize: +- Vite plugins +- Path aliases +- Build options +- Dev server settings + +### TypeScript Configuration + +Three separate configs serve different purposes: + +- **`tsconfig.json`** - Config for build tools (electron.vite.config.ts) + - Extends `tsconfig.node.json` + - Adds `electron-vite/node` types for Vite API + - Only includes the Vite config file + +- **`tsconfig.node.json`** - Config for main & preload (Node.js environment) + - Targets ES2020 with Node.js types + - Includes `src/main/**/*` and main process code + - No DOM or JSX support + +- **`tsconfig.renderer.json`** - Config for renderer (browser environment) + - Includes DOM and React types + - Supports JSX with `react-jsx` transform + - Path aliases for `@renderer/*` imports + - Includes `src/renderer/**/*` and UI code + +Each config is necessary because the three contexts (build tools, Node.js, browser) require different: +- Type definitions (Node vs DOM APIs) +- Language features (JSX support) +- Module resolution strategies +- Compilation targets + +## Troubleshooting -## Testing +### Port Already in Use -Once proto code is generated and backend services are running: +If dev server port is in use, electron-vite will automatically try another port. -1. Start the frontend: `npm run dev` -2. Visit `http://localhost:3000` -3. The health dashboard should display backend service status +### Type Errors -## Next Steps +Run `npm run typecheck` to see detailed TypeScript errors. -1. **Generate proto code**: Run `buf generate` from project root -2. **Implement features**: Add new features in `src/features/` -3. **Add components**: Use `npx shadcn-ui@latest add [component]` -4. **Connect to backend**: Update API calls once proto code is generated +### Build Errors -## Contributing +1. Clear build cache: `rm -rf out/` +2. Reinstall dependencies: `rm -rf node_modules && npm install` +3. Rebuild: `npm run build` -Follow these conventions: +### Hot Reload Not Working -- **Components**: PascalCase (e.g., `MyComponent.tsx`) -- **Hooks**: camelCase with "use" prefix (e.g., `useMyHook.ts`) -- **Utils**: camelCase (e.g., `myUtil.ts`) -- **Types**: PascalCase in `.types.ts` files -- **Features**: Organized by domain in `features/` directory +Restart the dev server with `npm run dev`. -## License +## Resources -[Add your license here] \ No newline at end of file +- [electron-vite Documentation](https://electron-vite.org/) +- [Electron Documentation](https://www.electronjs.org/docs/latest) +- [React Documentation](https://react.dev/) +- [Vite Documentation](https://vitejs.dev/) diff --git a/frontend/SETUP.md b/frontend/SETUP.md deleted file mode 100644 index 52c117f..0000000 --- a/frontend/SETUP.md +++ /dev/null @@ -1,209 +0,0 @@ -# Frontend Setup Guide - -## Quick Start - -```bash -# From the frontend directory -npm install -npm run dev -``` - -The app will run on `http://localhost:3000` - -## What's Included - -This frontend skeleton includes: - -### โœ… Core Technologies -- **Vite** - Fast build tool -- **React 18** with TypeScript -- **Tailwind CSS 3.4** - Utility-first CSS -- **ShadCN UI** - Beautiful, accessible components - -### โœ… State Management -- **Redux Toolkit** - Modern Redux with less boilerplate -- Typed hooks (`useAppDispatch`, `useAppSelector`) -- Feature-based organization - -### โœ… API Communication -- **Connect RPC** - Type-safe gRPC-Web client -- Ready for proto code generation -- Custom hooks for API calls - -### โœ… Components -Pre-built ShadCN components: -- Button -- Card -- Badge - -### โœ… Features -- **Health Dashboard** - Example feature showing backend service status -- Redux slice with async thunks -- Real-time status display - -## Directory Structure - -``` -src/ -โ”œโ”€โ”€ api/ # Connect RPC client -โ”‚ โ”œโ”€โ”€ client.ts # Transport & client setup -โ”‚ โ””โ”€โ”€ hooks.ts # React hooks for API calls -โ”œโ”€โ”€ components/ -โ”‚ โ””โ”€โ”€ ui/ # ShadCN UI components -โ”œโ”€โ”€ features/ # Feature modules -โ”‚ โ””โ”€โ”€ health/ # Health check feature -โ”‚ โ”œโ”€โ”€ HealthDashboard.tsx -โ”‚ โ””โ”€โ”€ healthSlice.ts -โ”œโ”€โ”€ lib/ -โ”‚ โ””โ”€โ”€ utils.ts # Utility functions -โ”œโ”€โ”€ store/ # Redux store -โ”‚ โ”œโ”€โ”€ index.ts # Store configuration -โ”‚ โ””โ”€โ”€ hooks.ts # Typed hooks -โ”œโ”€โ”€ App.tsx # Main component -โ”œโ”€โ”€ main.tsx # Entry point -โ””โ”€โ”€ index.css # Global styles + Tailwind -``` - -## Configuration Files - -- `vite.config.ts` - Vite configuration with path aliases -- `tailwind.config.js` - Tailwind CSS configuration -- `tsconfig.app.json` - TypeScript configuration with path aliases -- `components.json` - ShadCN UI configuration -- `.env.example` - Environment variables template - -## Next Steps - -### 1. Generate Proto Code - -From the project root: -```bash -buf generate -``` - -This will create TypeScript types in `frontend/src/generated/` - -### 2. Update API Client - -Once proto code is generated, update `src/api/client.ts`: - -```typescript -import { Gateway } from "@/generated/fi/gateway/v1/api_gateway_connect"; - -export const gatewayClient = createClient(Gateway, transport); -``` - -### 3. Use in Components - -```typescript -import { gatewayClient } from "@/api/client"; - -const response = await gatewayClient.healthCheck({}); -``` - -### 4. Add More ShadCN Components - -```bash -npx shadcn-ui@latest add dialog -npx shadcn-ui@latest add input -npx shadcn-ui@latest add form -``` - -See available components: https://ui.shadcn.com/docs/components - -### 5. Create New Features - -Follow the pattern in `features/health/`: -1. Create feature directory -2. Add Redux slice -3. Create components -4. Export from feature - -## Development Tips - -### Path Aliases -Use `@/` for imports: -```typescript -import { Button } from "@/components/ui/button"; -import { useAppDispatch } from "@/store/hooks"; -``` - -### Styling -- Use Tailwind utilities for most styling -- Use ShadCN components for complex UI -- CSS variables are in `src/index.css` for theming - -### State Management -```typescript -// Create a slice -export const mySlice = createSlice({ - name: 'myFeature', - initialState, - reducers: { ... }, - extraReducers: (builder) => { ... }, -}); - -// Use in components -const data = useAppSelector((state) => state.myFeature); -const dispatch = useAppDispatch(); -``` - -### API Calls -```typescript -// Option 1: Direct client usage -const response = await gatewayClient.someMethod({ ... }); - -// Option 2: Custom hook with loading states -const { execute, loading, error, data } = useApiCall( - async (args) => gatewayClient.someMethod(args) -); -``` - -## Testing the UI - -1. Start the frontend: `npm run dev` -2. Visit `http://localhost:3000` -3. You should see: - - Fi branding - - Health dashboard (placeholder data) - - Technology stack grid - - Responsive layout - -## Build for Production - -```bash -npm run build -``` - -Output will be in `dist/` directory. - -Preview the build: -```bash -npm run preview -``` - -## Common Issues - -### TypeScript Errors -Make sure path aliases are working: -- Check `tsconfig.app.json` has `baseUrl` and `paths` -- Check `vite.config.ts` has resolve aliases - -### Tailwind Not Working -- Ensure `index.css` is imported in `main.tsx` -- Check `tailwind.config.js` content paths -- Restart dev server - -### Component Not Found -- Verify import paths use `@/` alias -- Check component is exported properly -- Run `npm install` if dependency is missing - -## Resources - -- [Vite Docs](https://vite.dev/) -- [React Docs](https://react.dev/) -- [ShadCN UI](https://ui.shadcn.com/) -- [Tailwind CSS](https://tailwindcss.com/) -- [Redux Toolkit](https://redux-toolkit.js.org/) -- [Connect RPC](https://connectrpc.com/) diff --git a/frontend/components.json b/frontend/components.json index e2c49ef..9395d9b 100644 --- a/frontend/components.json +++ b/frontend/components.json @@ -5,7 +5,7 @@ "tsx": true, "tailwind": { "config": "tailwind.config.js", - "css": "src/index.css", + "css": "src/renderer/src/index.css", "baseColor": "slate", "cssVariables": true, "prefix": "" @@ -18,3 +18,4 @@ "hooks": "@/hooks" } } + diff --git a/electron/electron.vite.config.ts b/frontend/electron.vite.config.ts similarity index 65% rename from electron/electron.vite.config.ts rename to frontend/electron.vite.config.ts index 008e9c8..ef63fcf 100644 --- a/electron/electron.vite.config.ts +++ b/frontend/electron.vite.config.ts @@ -13,11 +13,16 @@ export default defineConfig({ plugins: [react()], resolve: { alias: { - '@': resolve(__dirname, './src'), + '@': resolve(__dirname, './src/renderer/src'), '@renderer': resolve(__dirname, './src/renderer/src'), '@services': resolve(__dirname, './src/services'), '@global': resolve(__dirname, './src/types/global'), '@hooks': resolve(__dirname, './src/renderer/src/hooks'), + '@components': resolve(__dirname, './src/renderer/src/components'), + '@lib': resolve(__dirname, './src/renderer/src/lib'), + '@store': resolve(__dirname, './src/renderer/src/store'), + '@api': resolve(__dirname, './src/renderer/src/api'), + '@pages': resolve(__dirname, './src/renderer/src/pages'), '@main': resolve(__dirname, './src/main'), '@preload': resolve(__dirname, './src/preload') } diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js deleted file mode 100644 index b19330b..0000000 --- a/frontend/eslint.config.js +++ /dev/null @@ -1,23 +0,0 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import tseslint from 'typescript-eslint' -import { defineConfig, globalIgnores } from 'eslint/config' - -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - js.configs.recommended, - tseslint.configs.recommended, - reactHooks.configs['recommended-latest'], - reactRefresh.configs.vite, - ], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - }, -]) diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index 072a57e..0000000 --- a/frontend/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - frontend - - -
- - - diff --git a/frontend/out/main/index.js b/frontend/out/main/index.js deleted file mode 100644 index e52c88d..0000000 --- a/frontend/out/main/index.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; -const electron = require("electron"); -const path = require("path"); -const utils = require("@electron-toolkit/utils"); -function createWindow() { - const mainWindow = new electron.BrowserWindow({ - width: 1200, - height: 800, - minWidth: 800, - minHeight: 600, - show: false, - autoHideMenuBar: true, - backgroundColor: "#ffffff", - webPreferences: { - preload: path.join(__dirname, "../preload/index.js"), - contextIsolation: true, - // SECURITY: Enable context isolation - sandbox: true, - // SECURITY: Enable sandbox - nodeIntegration: false, - // SECURITY: Disable node integration - webSecurity: true - // SECURITY: Enable web security - } - }); - mainWindow.on("ready-to-show", () => { - mainWindow.show(); - }); - if (utils.is.dev) { - mainWindow.webContents.openDevTools(); - } - mainWindow.webContents.setWindowOpenHandler((details) => { - require("electron").shell.openExternal(details.url); - return { action: "deny" }; - }); - if (utils.is.dev && process.env.ELECTRON_RENDERER_URL) { - mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL); - } else { - mainWindow.loadFile(path.join(__dirname, "../renderer/index.html")); - } - return mainWindow; -} -electron.app.whenReady().then(() => { - createWindow(); - electron.app.on("activate", function() { - if (electron.BrowserWindow.getAllWindows().length === 0) createWindow(); - }); -}); -electron.app.on("window-all-closed", () => { - if (process.platform !== "darwin") { - electron.app.quit(); - } -}); diff --git a/frontend/out/preload/index.js b/frontend/out/preload/index.js deleted file mode 100644 index b6d1994..0000000 --- a/frontend/out/preload/index.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -const electron = require("electron"); -const preload = require("@electron-toolkit/preload"); -const api = { - // Example: Send message to main process - send: (channel, data) => { - const validChannels = ["toMain"]; - if (validChannels.includes(channel)) { - electron.ipcRenderer.send(channel, data); - } - }, - // Example: Receive message from main process - receive: (channel, func) => { - const validChannels = ["fromMain"]; - if (validChannels.includes(channel)) { - electron.ipcRenderer.on(channel, (_event, ...args) => func(...args)); - } - }, - // Example: Invoke main process and wait for response - invoke: async (channel, data) => { - const validChannels = ["getData"]; - if (validChannels.includes(channel)) { - return await electron.ipcRenderer.invoke(channel, data); - } - } -}; -if (process.contextIsolated) { - try { - electron.contextBridge.exposeInMainWorld("electron", preload.electronAPI); - electron.contextBridge.exposeInMainWorld("api", api); - } catch (error) { - console.error("Error exposing APIs:", error); - } -} else { - window.electron = preload.electronAPI; - window.api = api; -} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b9ac153..71d129b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,47 +1,44 @@ { - "name": "frontend", - "version": "0.0.0", + "name": "fiapply-electron", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "frontend", - "version": "0.0.0", + "name": "fiapply-electron", + "version": "1.0.0", + "license": "ISC", "dependencies": { "@bufbuild/protobuf": "^2.9.0", - "@connectrpc/connect": "^2.1.0", "@connectrpc/connect-web": "^2.1.0", + "@electron-toolkit/preload": "^3.0.1", + "@electron-toolkit/utils": "^3.0.0", "@radix-ui/react-hover-card": "^1.1.15", "@radix-ui/react-separator": "^1.1.7", "@reduxjs/toolkit": "^2.9.0", + "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.544.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "lucide-react": "^0.545.0", + "postcss": "^8.5.6", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-redux": "^9.2.0", - "react-router-dom": "^7.9.3", - "shadcn": "^3.3.1", + "react-router-dom": "^7.9.4", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7", "tslog": "^4.10.2" }, "devDependencies": { - "@eslint/js": "^9.36.0", - "@types/node": "^24.6.0", - "@types/react": "^19.1.13", - "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.3", - "autoprefixer": "^10.4.21", - "eslint": "^9.36.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.20", - "globals": "^16.4.0", - "postcss": "^8.5.6", + "@types/node": "^22.10.2", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "electron": "^28.0.0", + "electron-vite": "^2.3.0", "tailwindcss": "^3.4.17", - "typescript": "~5.8.3", - "typescript-eslint": "^8.44.0", - "vite": "^7.1.7" + "typescript": "^5.8.3", + "vite": "^5.4.11" } }, "node_modules/@alloc/quick-lru": { @@ -56,31 +53,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@antfu/ni": { - "version": "25.0.0", - "resolved": "https://registry.npmjs.org/@antfu/ni/-/ni-25.0.0.tgz", - "integrity": "sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==", - "license": "MIT", - "dependencies": { - "ansis": "^4.0.0", - "fzf": "^0.5.2", - "package-manager-detector": "^1.3.0", - "tinyexec": "^1.0.1" - }, - "bin": { - "na": "bin/na.mjs", - "nci": "bin/nci.mjs", - "ni": "bin/ni.mjs", - "nlx": "bin/nlx.mjs", - "nr": "bin/nr.mjs", - "nun": "bin/nun.mjs", - "nup": "bin/nup.mjs" - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -95,6 +72,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -104,7 +82,9 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -134,6 +114,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", @@ -146,22 +127,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -174,53 +144,21 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", - "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -234,6 +172,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -247,61 +186,21 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -311,6 +210,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -320,6 +220,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -329,6 +230,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -342,6 +244,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.4" @@ -353,43 +256,13 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { + "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { @@ -431,48 +304,11 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", - "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", - "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-typescript": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -487,6 +323,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -505,6 +342,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -518,31 +356,15 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.9.0.tgz", "integrity": "sha512-rnJenoStJ8nvmt9Gzye8nkYd6V22xUAnu4086ER7h1zJ508vStko4pMvDeQ446ilDTFpV5wnoc5YS7XvMwwMqA==", - "license": "(Apache-2.0 AND BSD-3-Clause)" - }, - "node_modules/@bundled-es-modules/cookie": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", - "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==", - "license": "ISC", - "dependencies": { - "cookie": "^0.7.2" - } - }, - "node_modules/@bundled-es-modules/statuses": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", - "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", - "license": "ISC", - "dependencies": { - "statuses": "^2.0.1" - } + "license": "(Apache-2.0 AND BSD-3-Clause)", + "peer": true }, "node_modules/@connectrpc/connect": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.1.0.tgz", "integrity": "sha512-xhiwnYlJNHzmFsRw+iSPIwXR/xweTvTw8x5HiwWp10sbVtd4OpOXbRgE7V58xs1EC17fzusF1f5uOAy24OkBuA==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "@bufbuild/protobuf": "^2.7.0" } @@ -557,207 +379,49 @@ "@connectrpc/connect": "2.1.0" } }, - "node_modules/@dotenvx/dotenvx": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.51.0.tgz", - "integrity": "sha512-CbMGzyOYSyFF7d4uaeYwO9gpSBzLTnMmSmTVpCZjvpJFV69qYbjYPpzNnCz1mb2wIvEhjWjRwQWuBzTO0jITww==", - "license": "BSD-3-Clause", - "dependencies": { - "commander": "^11.1.0", - "dotenv": "^17.2.1", - "eciesjs": "^0.4.10", - "execa": "^5.1.1", - "fdir": "^6.2.0", - "ignore": "^5.3.0", - "object-treeify": "1.1.33", - "picomatch": "^4.0.2", - "which": "^4.0.0" - }, - "bin": { - "dotenvx": "src/cli/dotenvx.js" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/@electron-toolkit/preload": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@electron-toolkit/preload/-/preload-3.0.2.tgz", + "integrity": "sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==", "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", - "engines": { - "node": ">=16" + "electron": ">=13.0.0" } }, - "node_modules/@dotenvx/dotenvx/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/@electron-toolkit/utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@electron-toolkit/utils/-/utils-3.0.0.tgz", + "integrity": "sha512-GaXHDhiT7KCvMJjXdp/QqpYinq69T/Pdl49Z1XLf8mKGf63dnsODMWyrmIjEQ0z/vG7dO8qF3fvmI6Eb2lUNZA==", "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" + "peerDependencies": { + "electron": ">=13.0.0" } }, - "node_modules/@dotenvx/dotenvx/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", "engines": { "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/@dotenvx/dotenvx/node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/@dotenvx/dotenvx/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/@ecies/ciphers": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.4.tgz", - "integrity": "sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==", - "license": "MIT", - "engines": { - "bun": ">=1", - "deno": ">=2", - "node": ">=16" - }, - "peerDependencies": { - "@noble/ciphers": "^1.0.0" + "optionalDependencies": { + "global-agent": "^3.0.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", - "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -768,13 +432,13 @@ "aix" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", - "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -785,13 +449,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", - "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -802,13 +466,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", - "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -819,13 +483,13 @@ "android" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", - "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -836,13 +500,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", - "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -853,13 +517,13 @@ "darwin" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", - "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -870,13 +534,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", - "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -887,13 +551,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", - "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -904,13 +568,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", - "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -921,13 +585,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", - "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -938,13 +602,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", - "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -955,13 +619,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", - "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -972,13 +636,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", - "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -989,13 +653,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", - "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -1006,13 +670,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", - "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -1023,13 +687,13 @@ "linux" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", - "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -1040,30 +704,13 @@ "linux" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", - "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", - "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -1074,30 +721,13 @@ "netbsd" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", - "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", - "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -1108,30 +738,13 @@ "openbsd" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", - "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", - "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -1142,13 +755,13 @@ "sunos" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", - "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -1159,13 +772,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", - "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -1176,13 +789,13 @@ "win32" ], "engines": { - "node": ">=18" + "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", - "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -1193,161 +806,7 @@ "win32" ], "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.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" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", - "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.15.2", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" } }, "node_modules/@floating-ui/core": { @@ -1388,369 +847,80 @@ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=18.18.0" + "node": ">=12" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@inquirer/ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", - "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=6.0.0" } }, - "node_modules/@inquirer/confirm": { - "version": "5.1.18", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.18.tgz", - "integrity": "sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.2", - "@inquirer/type": "^3.0.8" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@inquirer/core": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", - "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/core/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/@inquirer/core/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/figures": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", - "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.19.1.tgz", - "integrity": "sha512-3Y2h3MZKjec1eAqSTBclATlX+AbC6n1LgfVzRMJLt3v6w0RCYgwLrjbxPDbhsYHt6Wdqc/aCceNJYgj448ELQQ==", - "license": "MIT", - "dependencies": { - "ajv": "^6.12.6", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.24.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@mswjs/interceptors": { - "version": "0.39.7", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.7.tgz", - "integrity": "sha512-sURvQbbKsq5f8INV54YJgJEdk8oxBanqkTiXXd33rKmofFCwZLhLRszPduMZ9TA9b8/1CHc/IJmOlBHJk2Q5AQ==", - "license": "MIT", - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@noble/ciphers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", - "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", - "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" + "node": ">= 8" } }, "node_modules/@nodelib/fs.stat": { @@ -1775,28 +945,6 @@ "node": ">= 8" } }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", - "license": "MIT" - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", - "license": "MIT", - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" - } - }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", - "license": "MIT" - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2222,16 +1370,16 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.38", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", - "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz", - "integrity": "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", "cpu": [ "arm" ], @@ -2243,9 +1391,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.3.tgz", - "integrity": "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", "cpu": [ "arm64" ], @@ -2257,9 +1405,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.3.tgz", - "integrity": "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", "cpu": [ "arm64" ], @@ -2271,9 +1419,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.3.tgz", - "integrity": "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", "cpu": [ "x64" ], @@ -2285,9 +1433,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.3.tgz", - "integrity": "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", "cpu": [ "arm64" ], @@ -2299,9 +1447,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.3.tgz", - "integrity": "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", "cpu": [ "x64" ], @@ -2313,9 +1461,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.3.tgz", - "integrity": "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", "cpu": [ "arm" ], @@ -2327,9 +1475,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.3.tgz", - "integrity": "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", "cpu": [ "arm" ], @@ -2341,9 +1489,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.3.tgz", - "integrity": "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", "cpu": [ "arm64" ], @@ -2355,9 +1503,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.3.tgz", - "integrity": "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", "cpu": [ "arm64" ], @@ -2369,9 +1517,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.3.tgz", - "integrity": "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", "cpu": [ "loong64" ], @@ -2383,9 +1531,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.3.tgz", - "integrity": "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", "cpu": [ "ppc64" ], @@ -2397,9 +1545,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.3.tgz", - "integrity": "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", "cpu": [ "riscv64" ], @@ -2411,9 +1559,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.3.tgz", - "integrity": "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", "cpu": [ "riscv64" ], @@ -2425,9 +1573,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.3.tgz", - "integrity": "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", "cpu": [ "s390x" ], @@ -2439,9 +1587,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.3.tgz", - "integrity": "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", "cpu": [ "x64" ], @@ -2453,9 +1601,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.3.tgz", - "integrity": "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", "cpu": [ "x64" ], @@ -2467,9 +1615,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.3.tgz", - "integrity": "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", "cpu": [ "arm64" ], @@ -2481,9 +1629,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.3.tgz", - "integrity": "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", "cpu": [ "arm64" ], @@ -2495,9 +1643,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.3.tgz", - "integrity": "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", "cpu": [ "ia32" ], @@ -2509,9 +1657,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.3.tgz", - "integrity": "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", "cpu": [ "x64" ], @@ -2523,9 +1671,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.3.tgz", - "integrity": "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", "cpu": [ "x64" ], @@ -2536,22 +1684,16 @@ "win32" ] }, - "node_modules/@sec-ant/readable-stream": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", - "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", - "license": "MIT" - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, "node_modules/@standard-schema/spec": { @@ -2566,30 +1708,16 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, - "node_modules/@ts-morph/common": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", - "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "license": "MIT", "dependencies": { - "fast-glob": "^3.3.3", - "minimatch": "^10.0.1", - "path-browserify": "^1.0.1" - } - }, - "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", - "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "defer-to-connect": "^2.0.0" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, "node_modules/@types/babel__core": { @@ -2637,11 +1765,17 @@ "@babel/types": "^7.28.2" } }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "license": "MIT" + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } }, "node_modules/@types/estree": { "version": "1.0.8", @@ -2650,48 +1784,68 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "license": "MIT" }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { - "version": "24.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.6.0.tgz", - "integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==", - "devOptional": true, + "version": "22.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.8.tgz", + "integrity": "sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==", "license": "MIT", "dependencies": { - "undici-types": "~7.13.0" + "undici-types": "~6.21.0" } }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/@types/react": { - "version": "19.1.16", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.16.tgz", - "integrity": "sha512-WBM/nDbEZmDUORKnh5i1bTnAz6vTohUf9b8esSMu+b24+srbaxa04UbJgWx78CVfNXA20sNu0odEIluZDFdCog==", + "version": "18.3.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", + "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { + "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "19.1.9", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", - "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { - "@types/react": "^19.0.0" + "@types/react": "^18.0.0" } }, - "node_modules/@types/statuses": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz", - "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", - "license": "MIT" + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/use-sync-external-store": { "version": "0.0.6", @@ -2699,363 +1853,41 @@ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", "license": "MIT" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.45.0.tgz", - "integrity": "sha512-HC3y9CVuevvWCl/oyZuI47dOeDF9ztdMEfMH8/DW/Mhwa9cCLnK1oD7JoTVGW/u7kFzNZUKUoyJEqkaJh5y3Wg==", - "dev": true, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "license": "MIT", + "optional": true, "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.45.0", - "@typescript-eslint/type-utils": "8.45.0", - "@typescript-eslint/utils": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.45.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "@types/node": "*" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.45.0.tgz", - "integrity": "sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==", + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.45.0", - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/typescript-estree": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0", - "debug": "^4.3.4" + "@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" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.45.0.tgz", - "integrity": "sha512-3pcVHwMG/iA8afdGLMuTibGR7pDsn9RjDev6CCB+naRsSYs2pns5QbinF4Xqw6YC/Sj3lMrm/Im0eMfaa61WUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.45.0", - "@typescript-eslint/types": "^8.45.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.45.0.tgz", - "integrity": "sha512-clmm8XSNj/1dGvJeO6VGH7EUSeA0FMs+5au/u3lrA3KfG8iJ4u8ym9/j2tTEoacAffdW1TVUzXO30W1JTJS7dA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.45.0.tgz", - "integrity": "sha512-aFdr+c37sc+jqNMGhH+ajxPXwjv9UtFZk79k8pLoJ6p4y0snmYpPA52GuWHgt2ZF4gRRW6odsEj41uZLojDt5w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.45.0.tgz", - "integrity": "sha512-bpjepLlHceKgyMEPglAeULX1vixJDgaKocp0RVJ5u4wLJIMNuKtUXIczpJCPcn2waII0yuvks/5m5/h3ZQKs0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/typescript-estree": "8.45.0", - "@typescript-eslint/utils": "8.45.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.45.0.tgz", - "integrity": "sha512-WugXLuOIq67BMgQInIxxnsSyRLFxdkJEJu8r4ngLR56q/4Q5LrbfkFRH27vMTjxEK8Pyz7QfzuZe/G15qQnVRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.45.0.tgz", - "integrity": "sha512-GfE1NfVbLam6XQ0LcERKwdTTPlLvHvXXhOeUGC1OXi4eQBoyy1iVsW+uzJ/J9jtCz6/7GCQ9MtrQ0fml/jWCnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.45.0", - "@typescript-eslint/tsconfig-utils": "8.45.0", - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/visitor-keys": "8.45.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.45.0.tgz", - "integrity": "sha512-bxi1ht+tLYg4+XV2knz/F7RVhU0k6VrSMc9sb8DQ6fyCTrGQLHfo7lDtN0QJjZjKkLA2ThrKuCdHEvLReqtIGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.45.0", - "@typescript-eslint/types": "8.45.0", - "@typescript-eslint/typescript-estree": "8.45.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.45.0.tgz", - "integrity": "sha512-qsaFBA3e09MIDAGFUrTk+dzqtfv1XPVz8t8d1f0ybTzrCY7BKiMC5cjrl1O/P7UmHsNyW90EYSkU/ZWpmXelag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.45.0", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", - "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.4", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.38", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -3065,29 +1897,17 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", - "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", - "license": "ISC", - "engines": { - "node": ">=14" - } - }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -3113,29 +1933,10 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "license": "MIT" }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/ast-types": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", - "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/autoprefixer": { "version": "10.4.21", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3176,9 +1977,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.9.tgz", - "integrity": "sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==", + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.13.tgz", + "integrity": "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -3196,35 +1997,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } + "optional": true }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -3240,9 +2027,9 @@ } }, "node_modules/browserslist": { - "version": "4.26.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz", - "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==", + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", "funding": [ { "type": "opencollective", @@ -3258,10 +2045,11 @@ } ], "license": "MIT", + "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.8.3", - "caniuse-lite": "^1.0.30001741", - "electron-to-chromium": "^1.5.218", + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, @@ -3272,51 +2060,50 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": "*" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10.6.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/camelcase-css": { @@ -3329,9 +2116,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001746", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001746.tgz", - "integrity": "sha512-eA7Ys/DGw+pnkWWSE/id29f2IcPHVoE8wxtvE5JdvD2V28VTDPy1yEeo11Guz0sJ4ZeGRcm3uaTcAqK1LXaphA==", + "version": "1.0.30001748", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", + "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", "funding": [ { "type": "opencollective", @@ -3348,23 +2135,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -3413,129 +2183,27 @@ "url": "https://polar.sh/cva" } }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "license": "MIT", "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" + "mimic-response": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", "engines": { "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" } }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/code-block-writer": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", - "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", - "license": "MIT" - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3563,95 +2231,20 @@ "node": ">= 6" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=18" } }, "node_modules/cross-spawn": { @@ -3687,19 +2280,10 @@ "devOptional": true, "license": "MIT" }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3713,126 +2297,172 @@ } } }, - "node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" + "dependencies": { + "mimic-response": "^3.1.0" }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "license": "MIT", + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT", + "optional": true + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "license": "Apache-2.0" }, - "node_modules/diff": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", - "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, - "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/electron": { + "version": "28.3.3", + "resolved": "https://registry.npmjs.org/electron/-/electron-28.3.3.tgz", + "integrity": "sha512-ObKMLSPNhomtCOBAxFS8P2DW/4umkh72ouZUlUKzXGtYuPzgr1SYhskhFWgzAsPtUzhL2CzyV2sfbHcEW4CXqw==", + "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "@electron/get": "^2.0.0", + "@types/node": "^18.11.18", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" }, "engines": { - "node": ">= 0.4" + "node": ">= 12.20.55" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" + "node_modules/electron-to-chromium": { + "version": "1.5.232", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.232.tgz", + "integrity": "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg==", + "license": "ISC" }, - "node_modules/eciesjs": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.15.tgz", - "integrity": "sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==", + "node_modules/electron-vite": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-2.3.0.tgz", + "integrity": "sha512-lsN2FymgJlp4k6MrcsphGqZQ9fKRdJKasoaiwIrAewN1tapYI/KINLdfEL7n10LuF0pPSNf/IqjzZbB5VINctg==", + "dev": true, "license": "MIT", "dependencies": { - "@ecies/ciphers": "^0.2.3", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "^1.9.1", - "@noble/hashes": "^1.8.0" + "@babel/core": "^7.24.7", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "cac": "^6.7.14", + "esbuild": "^0.21.5", + "magic-string": "^0.30.10", + "picocolors": "^1.0.1" + }, + "bin": { + "electron-vite": "bin/electron-vite.js" }, "engines": { - "bun": ">=1", - "deno": ">=2", - "node": ">=16" + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@swc/core": "^1.0.0", + "vite": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + } } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" + "node_modules/electron/node_modules/@types/node": { + "version": "18.19.129", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.129.tgz", + "integrity": "sha512-hrmi5jWt2w60ayox3iIXwpMEnfUvOLJCRtrOPbHtH15nTjvO7uhnelvrdAs0dO0/zl5DZ3ZbahiaXEVb54ca/A==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } }, - "node_modules/electron-to-chromium": { - "version": "1.5.227", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.227.tgz", - "integrity": "sha512-ITxuoPfJu3lsNWUi2lBM2PaBPYgH3uqmxut5vmBxgYvyI4AlJ6P3Cai1O76mOrkJCBzq0IxWg/NtqOrpu/0gKA==", - "license": "ISC" + "node_modules/electron/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -3840,13 +2470,13 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "once": "^1.4.0" } }, "node_modules/env-paths": { @@ -3858,20 +2488,12 @@ "node": ">=6" } }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", + "optional": true, "engines": { "node": ">= 0.4" } @@ -3881,26 +2503,22 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", + "optional": true, "engines": { "node": ">= 0.4" } }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } + "optional": true }, "node_modules/esbuild": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", - "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3908,35 +2526,32 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18" + "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.10", - "@esbuild/android-arm": "0.25.10", - "@esbuild/android-arm64": "0.25.10", - "@esbuild/android-x64": "0.25.10", - "@esbuild/darwin-arm64": "0.25.10", - "@esbuild/darwin-x64": "0.25.10", - "@esbuild/freebsd-arm64": "0.25.10", - "@esbuild/freebsd-x64": "0.25.10", - "@esbuild/linux-arm": "0.25.10", - "@esbuild/linux-arm64": "0.25.10", - "@esbuild/linux-ia32": "0.25.10", - "@esbuild/linux-loong64": "0.25.10", - "@esbuild/linux-mips64el": "0.25.10", - "@esbuild/linux-ppc64": "0.25.10", - "@esbuild/linux-riscv64": "0.25.10", - "@esbuild/linux-s390x": "0.25.10", - "@esbuild/linux-x64": "0.25.10", - "@esbuild/netbsd-arm64": "0.25.10", - "@esbuild/netbsd-x64": "0.25.10", - "@esbuild/openbsd-arm64": "0.25.10", - "@esbuild/openbsd-x64": "0.25.10", - "@esbuild/openharmony-arm64": "0.25.10", - "@esbuild/sunos-x64": "0.25.10", - "@esbuild/win32-arm64": "0.25.10", - "@esbuild/win32-ia32": "0.25.10", - "@esbuild/win32-x64": "0.25.10" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -3948,18 +2563,12 @@ "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=10" }, @@ -3967,315 +2576,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint": { - "version": "9.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", - "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.1", - "@eslint/core": "^0.15.2", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.36.0", - "@eslint/plugin-kit": "^0.3.5", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.22", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.22.tgz", - "integrity": "sha512-atkAG6QaJMGoTLc4MDAP+rqZcfwQuTIh2IqHWFLy2TEjxr0MOK+5BSG4RzL2564AAPpZkDRsZXAUz68kjnU6Ug==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": ">=8.40" - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/execa": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", - "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.6", - "figures": "^6.1.0", - "get-stream": "^9.0.0", - "human-signals": "^8.0.1", - "is-plain-obj": "^4.1.0", - "is-stream": "^4.0.1", - "npm-run-path": "^6.0.0", - "pretty-ms": "^9.2.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.1.1" + "extract-zip": "cli.js" }, "engines": { - "node": "^18.19.0 || >=20.5.0" + "node": ">= 10.17.0" }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } }, "node_modules/fast-glob": { "version": "3.3.3", @@ -4305,19 +2624,6 @@ "node": ">= 6" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -4327,55 +2633,13 @@ "reusify": "^1.0.4" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/figures": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", - "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", - "license": "MIT", - "dependencies": { - "is-unicode-supported": "^2.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" + "pend": "~1.2.0" } }, "node_modules/fill-range": { @@ -4390,61 +2654,6 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -4461,32 +2670,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -4496,27 +2683,18 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/fs-extra": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", - "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=14.14" + "node": ">=6 <7 || >=8" } }, "node_modules/fsevents": { @@ -4542,108 +2720,26 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fuzzysort": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-3.1.0.tgz", - "integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==", - "license": "MIT" - }, - "node_modules/fzf": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fzf/-/fzf-0.5.2.tgz", - "integrity": "sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==", - "license": "BSD-3-Clause" - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-own-enumerable-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz", - "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/get-stream": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", - "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "license": "MIT", "dependencies": { - "@sec-ant/readable-stream": "^0.4.1", - "is-stream": "^4.0.1" + "pump": "^3.0.0" }, "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4681,41 +2777,52 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "license": "BSD-3-Clause", + "optional": true, "dependencies": { - "balanced-match": "^1.0.0" + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/global-agent/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" + "optional": true, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", - "dev": true, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "license": "MIT", + "optional": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gopd": { @@ -4723,6 +2830,7 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", + "optional": true, "engines": { "node": ">= 0.4" }, @@ -4730,45 +2838,45 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/graphql": { - "version": "16.11.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", - "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4786,78 +2894,23 @@ "node": ">= 0.4" } }, - "node_modules/headers-polyfill": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", - "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", - "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "license": "MIT", - "engines": { - "node": ">= 4" + "node": ">=10.19.0" } }, "node_modules/immer": { @@ -4867,56 +2920,9 @@ "license": "MIT", "funding": { "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" + "url": "https://opencollective.com/immer" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4974,24 +2980,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-node-process": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", - "license": "MIT" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5001,72 +2989,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz", - "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/is-regexp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", - "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5103,22 +3025,11 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -5131,32 +3042,20 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "license": "MIT" }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC", + "optional": true }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -5166,13 +3065,10 @@ } }, "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -5181,35 +3077,11 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -5228,123 +3100,69 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "bin": { + "loose-envify": "cli.js" } }, - "node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/lucide-react": { - "version": "0.544.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz", - "integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==", + "version": "0.545.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.545.0.tgz", + "integrity": "sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", "license": "MIT", - "engines": { - "node": ">=18" + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5367,68 +3185,28 @@ "node": ">=8.6" } }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", + "node": ">=16 || 14 >=14.17" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minipass": { @@ -5446,147 +3224,39 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/msw": { - "version": "2.11.3", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.3.tgz", - "integrity": "sha512-878imp8jxIpfzuzxYfX0qqTq1IFQz/1/RBHs/PyirSjzi+xKM/RRfIpIqHSCWjH0GxidrjhgiiXC+DWXNDvT9w==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@inquirer/confirm": "^5.0.0", - "@mswjs/interceptors": "^0.39.1", - "@open-draft/deferred-promise": "^2.2.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "rettime": "^0.7.0", - "strict-event-emitter": "^0.5.1", - "tough-cookie": "^6.0.0", - "type-fest": "^4.26.1", - "until-async": "^3.0.2", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.8.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" } }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/node-releases": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", - "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", "license": "MIT" }, "node_modules/normalize-path": { @@ -5602,35 +3272,18 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "license": "MIT", "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5654,37 +3307,14 @@ "node": ">= 6" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "license": "MIT", + "optional": true, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-treeify": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", - "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" } }, "node_modules/once": { @@ -5696,133 +3326,13 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/emoji-regex": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", - "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", - "license": "MIT" - }, - "node_modules/ora/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/outvariant": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", - "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", - "license": "MIT" - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/package-json-from-dist": { @@ -5831,79 +3341,6 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, - "node_modules/package-manager-detector": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz", - "integrity": "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==", - "license": "MIT" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "license": "MIT", - "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" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", - "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5941,10 +3378,10 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "license": "ISC" }, - "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "license": "MIT" }, "node_modules/picocolors": { @@ -5983,15 +3420,6 @@ "node": ">= 6" } }, - "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -6011,6 +3439,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6141,88 +3570,23 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-ms": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", - "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", - "license": "MIT", - "dependencies": { - "parse-ms": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, "engines": { - "node": ">= 6" + "node": ">=0.4.0" } }, - "node_modules/prompts/node_modules/kleur": { + "node_modules/pump": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "node_modules/queue-microtask": { @@ -6245,65 +3609,43 @@ ], "license": "MIT" }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/react": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", - "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", - "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { - "scheduler": "^0.26.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^19.1.1" + "react": "^18.3.1" } }, "node_modules/react-redux": { @@ -6311,6 +3653,7 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", + "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -6340,9 +3683,9 @@ } }, "node_modules/react-router": { - "version": "7.9.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.3.tgz", - "integrity": "sha512-4o2iWCFIwhI/eYAIL43+cjORXYn/aRQPgtFRRZb3VzoyQ5Uej0Bmqj7437L97N9NJW4wnicSwLOLS+yCXfAPgg==", + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", + "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -6362,28 +3705,19 @@ } }, "node_modules/react-router-dom": { - "version": "7.9.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.3.tgz", - "integrity": "sha512-1QSbA0TGGFKTAc/aWjpfW/zoEukYfU4dc1dLkT/vvf54JoGMkW+fNA+3oyo2gWVW1GM7BxjJVHz5GnPJv40rvg==", + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.4.tgz", + "integrity": "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==", "license": "MIT", "dependencies": { - "react-router": "7.9.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, - "node_modules/react-router/node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "license": "MIT", + "react-router": "7.9.4" + }, "engines": { - "node": ">=18" + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" } }, "node_modules/read-cache": { @@ -6407,27 +3741,12 @@ "node": ">=8.10.0" } }, - "node_modules/recast": { - "version": "0.23.11", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", - "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", - "license": "MIT", - "dependencies": { - "ast-types": "^0.16.1", - "esprima": "~4.0.0", - "source-map": "~0.6.1", - "tiny-invariant": "^1.3.3", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">= 4" - } - }, "node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -6438,15 +3757,6 @@ "redux": "^5.0.0" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/reselect": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", @@ -6473,37 +3783,24 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "license": "MIT", - "engines": { - "node": ">=4" - } + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "license": "MIT", "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" + "lowercase-keys": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rettime": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz", - "integrity": "sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==", - "license": "MIT" - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -6514,10 +3811,28 @@ "node": ">=0.10.0" } }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/rollup": { - "version": "4.52.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.3.tgz", - "integrity": "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==", + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6531,57 +3846,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.3", - "@rollup/rollup-android-arm64": "4.52.3", - "@rollup/rollup-darwin-arm64": "4.52.3", - "@rollup/rollup-darwin-x64": "4.52.3", - "@rollup/rollup-freebsd-arm64": "4.52.3", - "@rollup/rollup-freebsd-x64": "4.52.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", - "@rollup/rollup-linux-arm-musleabihf": "4.52.3", - "@rollup/rollup-linux-arm64-gnu": "4.52.3", - "@rollup/rollup-linux-arm64-musl": "4.52.3", - "@rollup/rollup-linux-loong64-gnu": "4.52.3", - "@rollup/rollup-linux-ppc64-gnu": "4.52.3", - "@rollup/rollup-linux-riscv64-gnu": "4.52.3", - "@rollup/rollup-linux-riscv64-musl": "4.52.3", - "@rollup/rollup-linux-s390x-gnu": "4.52.3", - "@rollup/rollup-linux-x64-gnu": "4.52.3", - "@rollup/rollup-linux-x64-musl": "4.52.3", - "@rollup/rollup-openharmony-arm64": "4.52.3", - "@rollup/rollup-win32-arm64-msvc": "4.52.3", - "@rollup/rollup-win32-ia32-msvc": "4.52.3", - "@rollup/rollup-win32-x64-gnu": "4.52.3", - "@rollup/rollup-win32-x64-msvc": "4.52.3", + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", "fsevents": "~2.3.2" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/router/node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6605,37 +3894,14 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT" + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/semver": { "version": "6.3.1", @@ -6646,41 +3912,27 @@ "semver": "bin/semver.js" } }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } + "optional": true }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", "license": "MIT", + "optional": true, "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" + "type-fest": "^0.13.1" }, "engines": { - "node": ">= 18" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/set-cookie-parser": { @@ -6689,62 +3941,6 @@ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", "license": "MIT" }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shadcn": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/shadcn/-/shadcn-3.3.1.tgz", - "integrity": "sha512-sgai5gahy/TiyTiqJEwIFpAuPhmkpt7sGVdRfcmNH53Yc3yI57+zFVmIaqbTST0jP/7tSqZuI0aSllXL2HIw5w==", - "license": "MIT", - "dependencies": { - "@antfu/ni": "^25.0.0", - "@babel/core": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/plugin-transform-typescript": "^7.28.0", - "@babel/preset-typescript": "^7.27.1", - "@dotenvx/dotenvx": "^1.48.4", - "@modelcontextprotocol/sdk": "^1.17.2", - "browserslist": "^4.26.2", - "commander": "^14.0.0", - "cosmiconfig": "^9.0.0", - "dedent": "^1.6.0", - "deepmerge": "^4.3.1", - "diff": "^8.0.2", - "execa": "^9.6.0", - "fast-glob": "^3.3.3", - "fs-extra": "^11.3.1", - "fuzzysort": "^3.1.0", - "https-proxy-agent": "^7.0.6", - "kleur": "^4.1.5", - "msw": "^2.10.4", - "node-fetch": "^3.3.2", - "ora": "^8.2.0", - "postcss": "^8.5.6", - "prompts": "^2.4.2", - "recast": "^0.23.11", - "stringify-object": "^5.0.0", - "ts-morph": "^26.0.0", - "tsconfig-paths": "^4.2.0", - "zod": "^3.24.1", - "zod-to-json-schema": "^3.24.6" - }, - "bin": { - "shadcn": "dist/index.js" - } - }, - "node_modules/shadcn/node_modules/commander": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", - "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", - "license": "MIT", - "engines": { - "node": ">=20" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6766,78 +3962,6 @@ "node": ">=8" } }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -6850,21 +3974,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "license": "MIT" - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -6874,32 +3983,12 @@ "node": ">=0.10.0" } }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strict-event-emitter": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", - "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", - "license": "MIT" + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause", + "optional": true }, "node_modules/string-width": { "version": "5.1.2", @@ -6960,23 +4049,6 @@ "node": ">=8" } }, - "node_modules/stringify-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz", - "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==", - "license": "BSD-2-Clause", - "dependencies": { - "get-own-enumerable-keys": "^1.0.0", - "is-obj": "^3.0.0", - "is-regexp": "^3.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/yeoman/stringify-object?sponsor=1" - } - }, "node_modules/strip-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", @@ -7014,40 +4086,6 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", - "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -7070,17 +4108,16 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "license": "Apache-2.0", "dependencies": { - "has-flag": "^4.0.0" + "debug": "^4.1.0" }, "engines": { - "node": ">=8" + "node": ">= 8.0" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -7110,6 +4147,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -7162,94 +4200,16 @@ }, "node_modules/thenify-all": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", - "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tldts": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.16.tgz", - "integrity": "sha512-5bdPHSwbKTeHmXrgecID4Ljff8rQjv7g8zKQPkCozRo2HWWni+p310FSn5ImI+9kWw9kK4lzOB5q/a6iv0IJsw==", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "license": "MIT", "dependencies": { - "tldts-core": "^7.0.16" + "thenify": ">= 3.1.0 < 4" }, - "bin": { - "tldts": "bin/cli.js" + "engines": { + "node": ">=0.8" } }, - "node_modules/tldts-core": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.16.tgz", - "integrity": "sha512-XHhPmHxphLi+LGbH0G/O7dmUH9V65OY20R7vH8gETHsp5AZCjBk9l8sqmRKLaGOxnETU7XNSDUPtewAy/K6jbA==", - "license": "MIT" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7262,40 +4222,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^7.0.5" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -7314,80 +4240,24 @@ "url": "https://github.com/fullstack-build/tslog?sponsor=1" } }, - "node_modules/ts-morph": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", - "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", - "license": "MIT", - "dependencies": { - "@ts-morph/common": "~0.27.0", - "code-block-writer": "^13.0.3" - } - }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "license": "MIT", - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "license": "(MIT OR CC0-1.0)", + "optional": true, "engines": { - "node": ">=16" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "devOptional": true, + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7397,74 +4267,19 @@ "node": ">=14.17" } }, - "node_modules/typescript-eslint": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.45.0.tgz", - "integrity": "sha512-qzDmZw/Z5beNLUrXfd0HIW6MzIaAV5WNDxmMs9/3ojGOpYavofgNAAD/nC6tGV2PczIi0iw8vot2eAe/sBn7zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.45.0", - "@typescript-eslint/parser": "8.45.0", - "@typescript-eslint/typescript-estree": "8.45.0", - "@typescript-eslint/utils": "8.45.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, "node_modules/undici-types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.13.0.tgz", - "integrity": "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==", - "devOptional": true, + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, - "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "license": "MIT", "engines": { - "node": ">= 0.8" - } - }, - "node_modules/until-async": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz", - "integrity": "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/kettanaito" + "node": ">= 4.0.0" } }, "node_modules/update-browserslist-db": { @@ -7497,19 +4312,10 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/use-sync-external-store": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", - "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -7521,34 +4327,23 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/vite": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz", - "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", + "version": "5.4.20", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", + "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -7557,25 +4352,19 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, - "jiti": { - "optional": true - }, "less": { "optional": true }, @@ -7596,55 +4385,9 @@ }, "terser": { "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true } } }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7660,16 +4403,6 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -7714,6 +4447,21 @@ "node": ">=8" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -7746,37 +4494,17 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -7791,127 +4519,14 @@ "node": ">= 14.6" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yoctocolors-cjs": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", - "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.6", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", - "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } } } diff --git a/frontend/package.json b/frontend/package.json index 5371100..e5b450d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,48 +1,49 @@ { - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", + "name": "fiapply-electron", + "version": "1.0.0", + "description": "FiApply Desktop Application - Electron Vite", + "main": "./out/main/index.js", + "author": "Firelight Innovations", + "license": "ISC", "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" + "dev": "electron-vite dev", + "build": "electron-vite build", + "preview": "electron-vite preview", + "start": "electron-vite preview", + "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", + "typecheck:renderer": "tsc --noEmit -p tsconfig.renderer.json --composite false", + "typecheck": "npm run typecheck:node && npm run typecheck:renderer" }, "dependencies": { "@bufbuild/protobuf": "^2.9.0", - "@connectrpc/connect": "^2.1.0", "@connectrpc/connect-web": "^2.1.0", + "@electron-toolkit/preload": "^3.0.1", + "@electron-toolkit/utils": "^3.0.0", "@radix-ui/react-hover-card": "^1.1.15", "@radix-ui/react-separator": "^1.1.7", "@reduxjs/toolkit": "^2.9.0", + "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.544.0", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "lucide-react": "^0.545.0", + "postcss": "^8.5.6", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-redux": "^9.2.0", - "react-router-dom": "^7.9.3", - "shadcn": "^3.3.1", + "react-router-dom": "^7.9.4", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7", "tslog": "^4.10.2" }, "devDependencies": { - "@eslint/js": "^9.36.0", - "@types/node": "^24.6.0", - "@types/react": "^19.1.13", - "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.3", - "autoprefixer": "^10.4.21", - "eslint": "^9.36.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.20", - "globals": "^16.4.0", - "postcss": "^8.5.6", + "@types/node": "^22.10.2", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "electron": "^28.0.0", + "electron-vite": "^2.3.0", "tailwindcss": "^3.4.17", - "typescript": "~5.8.3", - "typescript-eslint": "^8.44.0", - "vite": "^7.1.7" + "typescript": "^5.8.3", + "vite": "^5.4.11" } } diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js index 2e7af2b..b4a6220 100644 --- a/frontend/postcss.config.js +++ b/frontend/postcss.config.js @@ -4,3 +4,4 @@ export default { autoprefixer: {}, }, } + diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/frontend/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx deleted file mode 100644 index 8c186c4..0000000 --- a/frontend/src/App.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Main App Component - * Entry point for the Fi application - */ -import { HealthDashboard } from './pages/HealthDashboard.tsx'; -import Dashboard from './pages/Dashboard.tsx'; -import Landing from './pages/Landing.tsx'; - -import { BrowserRouter, Routes, Route} from 'react-router-dom'; - -function App() { - return ( - - - }> - }> - }> - - - ); -} - -export default App; \ No newline at end of file diff --git a/frontend/src/features/health/HealthDashboard.tsx b/frontend/src/features/health/HealthDashboard.tsx deleted file mode 100644 index 4ec654d..0000000 --- a/frontend/src/features/health/HealthDashboard.tsx +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Health Dashboard Component - * Displays the status of backend services - */ -import { useEffect } from 'react'; -import { useAppDispatch, useAppSelector } from '@/store/hooks'; -import { checkHealth } from '@/store/healthSlice'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; -import { Activity, RefreshCw } from 'lucide-react'; - -export function HealthDashboard() { - const dispatch = useAppDispatch(); - const { status, services, error, lastChecked } = useAppSelector((state) => state.health); - - useEffect(() => { - // Check health on mount - dispatch(checkHealth()); - }, [dispatch]); - - const handleRefresh = () => { - dispatch(checkHealth()); - }; - - const getStatusVariant = (status: string) => { - switch (status.toLowerCase()) { - case 'healthy': - case 'ok': - return 'success'; - case 'degraded': - return 'secondary'; - case 'unhealthy': - return 'destructive'; - default: - return 'outline'; - } - }; - - return ( - - -
-
- - Backend Services Health -
- -
- - {lastChecked - ? `Last checked: ${new Date(lastChecked).toLocaleTimeString()}` - : 'Loading service status...'} - -
- - {error && ( -
- Error: {error} -
- )} - -
- {Object.entries(services).map(([serviceName, serviceStatus]) => ( -
-
-
{serviceName.replace(/-/g, ' ')}
-
- - {serviceStatus} - -
- ))} - - {Object.keys(services).length === 0 && status !== 'loading' && ( -
- No services found. Click refresh to check status. -
- )} - - {status === 'loading' && Object.keys(services).length === 0 && ( -
- Checking service status... -
- )} -
-
-
- ); -} diff --git a/frontend/src/generated/rag_engine_connect.ts b/frontend/src/generated/rag_engine_connect.ts index f5bf7a9..cd4d5ee 100644 --- a/frontend/src/generated/rag_engine_connect.ts +++ b/frontend/src/generated/rag_engine_connect.ts @@ -3,7 +3,7 @@ /* eslint-disable */ // @ts-nocheck -import { EmbeddingRequest, EmbeddingResponse, RetrieveRequest, RetrieveResponse, SearchRequest, SearchResponse, StoreDocumentRequest, StoreDocumentResponse } from "./rag_engine_pb.js"; +import { EmbeddingRequest, EmbeddingResponse, EmbedScholarshipBatchRequest, EmbedScholarshipBatchResponse, InitRequest, InitResponse, RetrieveRequest, RetrieveResponse, SearchRequest, SearchResponse, StoreDocumentRequest, StoreDocumentResponse } from "./rag_engine_pb.js"; import { MethodKind } from "@bufbuild/protobuf"; /** @@ -61,3 +61,38 @@ export const RAGEngine = { } } as const; +/** + * ========================================= + * VectorDBService - declare RPC methods + * ========================================= + * + * @generated from service fi.rag.v1.VectorDBService + */ +export const VectorDBService = { + typeName: "fi.rag.v1.VectorDBService", + methods: { + /** + * Initialize vector DB connection or collection + * + * @generated from rpc fi.rag.v1.VectorDBService.Init + */ + init: { + name: "Init", + I: InitRequest, + O: InitResponse, + kind: MethodKind.Unary, + }, + /** + * Embed a batch of scholarships and store them + * + * @generated from rpc fi.rag.v1.VectorDBService.EmbedScholarshipBatch + */ + embedScholarshipBatch: { + name: "EmbedScholarshipBatch", + I: EmbedScholarshipBatchRequest, + O: EmbedScholarshipBatchResponse, + kind: MethodKind.Unary, + }, + } +} as const; + diff --git a/frontend/src/generated/rag_engine_pb.ts b/frontend/src/generated/rag_engine_pb.ts index df45dca..83b3e69 100644 --- a/frontend/src/generated/rag_engine_pb.ts +++ b/frontend/src/generated/rag_engine_pb.ts @@ -13,7 +13,7 @@ import type { JsonObject, Message } from "@bufbuild/protobuf"; * Describes the file rag_engine.proto. */ export const file_rag_engine: GenFile = /*@__PURE__*/ - fileDesc("ChByYWdfZW5naW5lLnByb3RvEglmaS5yYWcudjEiewoUU3RvcmVEb2N1bWVudFJlcXVlc3QSEwoLZG9jdW1lbnRfaWQYASABKAkSDwoHY29udGVudBgCIAEoCRIpCghtZXRhZGF0YRgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSEgoKc291cmNlX3VybBgEIAEoCSJ4ChVTdG9yZURvY3VtZW50UmVzcG9uc2USEwoLZG9jdW1lbnRfaWQYASABKAkSDwoHc3VjY2VzcxgCIAEoCBIVCg1jaHVua3Nfc3RvcmVkGAMgASgFEiIKBWVycm9yGAQgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIl8KD1JldHJpZXZlUmVxdWVzdBINCgVxdWVyeRgBIAEoCRITCgttYXhfcmVzdWx0cxgCIAEoBRIoCgdmaWx0ZXJzGAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdCJfChBSZXRyaWV2ZVJlc3BvbnNlEicKBmNodW5rcxgBIAMoCzIXLmZpLnJhZy52MS5Db250ZXh0Q2h1bmsSIgoFZXJyb3IYAiABKAsyEy5maS5jb21tb24udjEuRXJyb3IicwoMQ29udGV4dENodW5rEg8KB2NvbnRlbnQYASABKAkSFwoPcmVsZXZhbmNlX3Njb3JlGAIgASgBEikKCG1ldGFkYXRhGAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIOCgZzb3VyY2UYBCABKAkiIAoQRW1iZWRkaW5nUmVxdWVzdBIMCgR0ZXh0GAEgASgJIkoKEUVtYmVkZGluZ1Jlc3BvbnNlEhEKCWVtYmVkZGluZxgBIAMoAhIiCgVlcnJvchgCIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvciJXCg1TZWFyY2hSZXF1ZXN0Eg0KBXF1ZXJ5GAEgASgJEg0KBWxpbWl0GAIgASgFEigKB2ZpbHRlcnMYAyABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Il4KDlNlYXJjaFJlc3BvbnNlEigKB3Jlc3VsdHMYASADKAsyFy5maS5yYWcudjEuU2VhcmNoUmVzdWx0EiIKBWVycm9yGAIgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIm4KDFNlYXJjaFJlc3VsdBITCgtkb2N1bWVudF9pZBgBIAEoCRIPCgdjb250ZW50GAIgASgJEg0KBXNjb3JlGAMgASgBEikKCG1ldGFkYXRhGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdDLCAgoJUkFHRW5naW5lElIKDVN0b3JlRG9jdW1lbnQSHy5maS5yYWcudjEuU3RvcmVEb2N1bWVudFJlcXVlc3QaIC5maS5yYWcudjEuU3RvcmVEb2N1bWVudFJlc3BvbnNlEkoKD1JldHJpZXZlQ29udGV4dBIaLmZpLnJhZy52MS5SZXRyaWV2ZVJlcXVlc3QaGy5maS5yYWcudjEuUmV0cmlldmVSZXNwb25zZRJOChFHZW5lcmF0ZUVtYmVkZGluZxIbLmZpLnJhZy52MS5FbWJlZGRpbmdSZXF1ZXN0GhwuZmkucmFnLnYxLkVtYmVkZGluZ1Jlc3BvbnNlEkUKDlNlbWFudGljU2VhcmNoEhguZmkucmFnLnYxLlNlYXJjaFJlcXVlc3QaGS5maS5yYWcudjEuU2VhcmNoUmVzcG9uc2VCogEKDWNvbS5maS5yYWcudjFCDlJhZ0VuZ2luZVByb3RvUAFaO2dpdGh1Yi5jb20vRmlyZWxpZ2h0LUlubm92YXRpb25zL0ZpQXBwbHkvcHJvdG8vcmFnL3YxO3JhZ3YxogIDRlJYqgIJRmkuUmFnLlYxygIJRmlcUmFnXFYx4gIVRmlcUmFnXFYxXEdQQk1ldGFkYXRh6gILRmk6OlJhZzo6VjFiBnByb3RvMw", [file_common, file_google_protobuf_empty, file_google_protobuf_struct]); + fileDesc("ChByYWdfZW5naW5lLnByb3RvEglmaS5yYWcudjEiewoUU3RvcmVEb2N1bWVudFJlcXVlc3QSEwoLZG9jdW1lbnRfaWQYASABKAkSDwoHY29udGVudBgCIAEoCRIpCghtZXRhZGF0YRgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSEgoKc291cmNlX3VybBgEIAEoCSJ4ChVTdG9yZURvY3VtZW50UmVzcG9uc2USEwoLZG9jdW1lbnRfaWQYASABKAkSDwoHc3VjY2VzcxgCIAEoCBIVCg1jaHVua3Nfc3RvcmVkGAMgASgFEiIKBWVycm9yGAQgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIl8KD1JldHJpZXZlUmVxdWVzdBINCgVxdWVyeRgBIAEoCRITCgttYXhfcmVzdWx0cxgCIAEoBRIoCgdmaWx0ZXJzGAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdCJfChBSZXRyaWV2ZVJlc3BvbnNlEicKBmNodW5rcxgBIAMoCzIXLmZpLnJhZy52MS5Db250ZXh0Q2h1bmsSIgoFZXJyb3IYAiABKAsyEy5maS5jb21tb24udjEuRXJyb3IicwoMQ29udGV4dENodW5rEg8KB2NvbnRlbnQYASABKAkSFwoPcmVsZXZhbmNlX3Njb3JlGAIgASgBEikKCG1ldGFkYXRhGAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIOCgZzb3VyY2UYBCABKAkiIAoQRW1iZWRkaW5nUmVxdWVzdBIMCgR0ZXh0GAEgASgJIkoKEUVtYmVkZGluZ1Jlc3BvbnNlEhEKCWVtYmVkZGluZxgBIAMoAhIiCgVlcnJvchgCIAEoCzITLmZpLmNvbW1vbi52MS5FcnJvciJXCg1TZWFyY2hSZXF1ZXN0Eg0KBXF1ZXJ5GAEgASgJEg0KBWxpbWl0GAIgASgFEigKB2ZpbHRlcnMYAyABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Il4KDlNlYXJjaFJlc3BvbnNlEigKB3Jlc3VsdHMYASADKAsyFy5maS5yYWcudjEuU2VhcmNoUmVzdWx0EiIKBWVycm9yGAIgASgLMhMuZmkuY29tbW9uLnYxLkVycm9yIm4KDFNlYXJjaFJlc3VsdBITCgtkb2N1bWVudF9pZBgBIAEoCRIPCgdjb250ZW50GAIgASgJEg0KBXNjb3JlGAMgASgBEikKCG1ldGFkYXRhGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdCJBCgtJbml0UmVxdWVzdBIZChFjb25uZWN0aW9uX3N0cmluZxgBIAEoCRIXCg9jb2xsZWN0aW9uX25hbWUYAiABKAkiQwoMSW5pdFJlc3BvbnNlEg8KB3N1Y2Nlc3MYASABKAgSIgoFZXJyb3IYAiABKAsyEy5maS5jb21tb24udjEuRXJyb3IiTAocRW1iZWRTY2hvbGFyc2hpcEJhdGNoUmVxdWVzdBIsCgxzY2hvbGFyc2hpcHMYASADKAsyFi5maS5yYWcudjEuU2Nob2xhcnNoaXAiWwodRW1iZWRTY2hvbGFyc2hpcEJhdGNoUmVzcG9uc2USFgoOdG90YWxfZW1iZWRkZWQYASABKAUSIgoFZXJyb3IYAiABKAsyEy5maS5jb21tb24udjEuRXJyb3IiWwoIRG9jdW1lbnQSEwoLZG9jdW1lbnRfaWQYASABKAkSDwoHY29udGVudBgCIAEoCRIpCghtZXRhZGF0YRgDIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QivgEKC1NjaG9sYXJzaGlwEgoKAmlkGAEgASgFEgwKBG5hbWUYAiABKAkSEwoLZGVzY3JpcHRpb24YAyABKAkSDwoHbWluX2dwYRgEIAEoARIXCg9lbGlnaWJsZV9tYWpvcnMYBSADKAkSHAoUY2l0aXplbnNoaXBfcmVxdWlyZWQYBiABKAkSEAoIbG9jYXRpb24YByABKAkSFAoMYXdhcmRfYW1vdW50GAggASgJEhAKCGtleXdvcmRzGAkgAygJMsICCglSQUdFbmdpbmUSUgoNU3RvcmVEb2N1bWVudBIfLmZpLnJhZy52MS5TdG9yZURvY3VtZW50UmVxdWVzdBogLmZpLnJhZy52MS5TdG9yZURvY3VtZW50UmVzcG9uc2USSgoPUmV0cmlldmVDb250ZXh0EhouZmkucmFnLnYxLlJldHJpZXZlUmVxdWVzdBobLmZpLnJhZy52MS5SZXRyaWV2ZVJlc3BvbnNlEk4KEUdlbmVyYXRlRW1iZWRkaW5nEhsuZmkucmFnLnYxLkVtYmVkZGluZ1JlcXVlc3QaHC5maS5yYWcudjEuRW1iZWRkaW5nUmVzcG9uc2USRQoOU2VtYW50aWNTZWFyY2gSGC5maS5yYWcudjEuU2VhcmNoUmVxdWVzdBoZLmZpLnJhZy52MS5TZWFyY2hSZXNwb25zZTK2AQoPVmVjdG9yREJTZXJ2aWNlEjcKBEluaXQSFi5maS5yYWcudjEuSW5pdFJlcXVlc3QaFy5maS5yYWcudjEuSW5pdFJlc3BvbnNlEmoKFUVtYmVkU2Nob2xhcnNoaXBCYXRjaBInLmZpLnJhZy52MS5FbWJlZFNjaG9sYXJzaGlwQmF0Y2hSZXF1ZXN0GiguZmkucmFnLnYxLkVtYmVkU2Nob2xhcnNoaXBCYXRjaFJlc3BvbnNlQqIBCg1jb20uZmkucmFnLnYxQg5SYWdFbmdpbmVQcm90b1ABWjtnaXRodWIuY29tL0ZpcmVsaWdodC1Jbm5vdmF0aW9ucy9GaUFwcGx5L3Byb3RvL3JhZy92MTtyYWd2MaICA0ZSWKoCCUZpLlJhZy5WMcoCCUZpXFJhZ1xWMeICFUZpXFJhZ1xWMVxHUEJNZXRhZGF0YeoCC0ZpOjpSYWc6OlYxYgZwcm90bzM", [file_common, file_google_protobuf_empty, file_google_protobuf_struct]); /** * @generated from message fi.rag.v1.StoreDocumentRequest @@ -338,6 +338,197 @@ export type SearchResult = Message<"fi.rag.v1.SearchResult"> & { export const SearchResultSchema: GenMessage = /*@__PURE__*/ messageDesc(file_rag_engine, 9); +/** + * @generated from message fi.rag.v1.InitRequest + */ +export type InitRequest = Message<"fi.rag.v1.InitRequest"> & { + /** + * e.g. "postgresql://user:pass@localhost/db" + * + * @generated from field: string connection_string = 1; + */ + connectionString: string; + + /** + * @generated from field: string collection_name = 2; + */ + collectionName: string; +}; + +/** + * Describes the message fi.rag.v1.InitRequest. + * Use `create(InitRequestSchema)` to create a new message. + */ +export const InitRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_rag_engine, 10); + +/** + * @generated from message fi.rag.v1.InitResponse + */ +export type InitResponse = Message<"fi.rag.v1.InitResponse"> & { + /** + * @generated from field: bool success = 1; + */ + success: boolean; + + /** + * @generated from field: fi.common.v1.Error error = 2; + */ + error?: Error; +}; + +/** + * Describes the message fi.rag.v1.InitResponse. + * Use `create(InitResponseSchema)` to create a new message. + */ +export const InitResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_rag_engine, 11); + +/** + * @generated from message fi.rag.v1.EmbedScholarshipBatchRequest + */ +export type EmbedScholarshipBatchRequest = Message<"fi.rag.v1.EmbedScholarshipBatchRequest"> & { + /** + * Example dataclass converted below + * + * @generated from field: repeated fi.rag.v1.Scholarship scholarships = 1; + */ + scholarships: Scholarship[]; +}; + +/** + * Describes the message fi.rag.v1.EmbedScholarshipBatchRequest. + * Use `create(EmbedScholarshipBatchRequestSchema)` to create a new message. + */ +export const EmbedScholarshipBatchRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_rag_engine, 12); + +/** + * @generated from message fi.rag.v1.EmbedScholarshipBatchResponse + */ +export type EmbedScholarshipBatchResponse = Message<"fi.rag.v1.EmbedScholarshipBatchResponse"> & { + /** + * @generated from field: int32 total_embedded = 1; + */ + totalEmbedded: number; + + /** + * @generated from field: fi.common.v1.Error error = 2; + */ + error?: Error; +}; + +/** + * Describes the message fi.rag.v1.EmbedScholarshipBatchResponse. + * Use `create(EmbedScholarshipBatchResponseSchema)` to create a new message. + */ +export const EmbedScholarshipBatchResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_rag_engine, 13); + +/** + * may change + * + * @generated from message fi.rag.v1.Document + */ +export type Document = Message<"fi.rag.v1.Document"> & { + /** + * @generated from field: string document_id = 1; + */ + documentId: string; + + /** + * @generated from field: string content = 2; + */ + content: string; + + /** + * @generated from field: google.protobuf.Struct metadata = 3; + */ + metadata?: JsonObject; +}; + +/** + * Describes the message fi.rag.v1.Document. + * Use `create(DocumentSchema)` to create a new message. + */ +export const DocumentSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_rag_engine, 14); + +/** + * @generated from message fi.rag.v1.Scholarship + */ +export type Scholarship = Message<"fi.rag.v1.Scholarship"> & { + /** + * Unique scholarship identifier + * + * @generated from field: int32 id = 1; + */ + id: number; + + /** + * Scholarship name + * + * @generated from field: string name = 2; + */ + name: string; + + /** + * Scholarship description or summary + * + * @generated from field: string description = 3; + */ + description: string; + + /** + * Minimum GPA required (e.g. 3.5) + * + * @generated from field: double min_gpa = 4; + */ + minGpa: number; + + /** + * Eligible majors (e.g. "Computer Science", "Engineering") + * + * @generated from field: repeated string eligible_majors = 5; + */ + eligibleMajors: string[]; + + /** + * Citizenship requirement (optional, can be null) + * + * @generated from field: string citizenship_required = 6; + */ + citizenshipRequired: string; + + /** + * Location requirement or region (optional) + * + * @generated from field: string location = 7; + */ + location: string; + + /** + * Award amount or range, kept as a string for flexibility + * + * @generated from field: string award_amount = 8; + */ + awardAmount: string; + + /** + * Keywords for semantic search / classification + * + * @generated from field: repeated string keywords = 9; + */ + keywords: string[]; +}; + +/** + * Describes the message fi.rag.v1.Scholarship. + * Use `create(ScholarshipSchema)` to create a new message. + */ +export const ScholarshipSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_rag_engine, 15); + /** * RAG Engine - Retrieval-Augmented Generation processing * @@ -387,3 +578,34 @@ export const RAGEngine: GenService<{ }> = /*@__PURE__*/ serviceDesc(file_rag_engine, 0); +/** + * ========================================= + * VectorDBService - declare RPC methods + * ========================================= + * + * @generated from service fi.rag.v1.VectorDBService + */ +export const VectorDBService: GenService<{ + /** + * Initialize vector DB connection or collection + * + * @generated from rpc fi.rag.v1.VectorDBService.Init + */ + init: { + methodKind: "unary"; + input: typeof InitRequestSchema; + output: typeof InitResponseSchema; + }, + /** + * Embed a batch of scholarships and store them + * + * @generated from rpc fi.rag.v1.VectorDBService.EmbedScholarshipBatch + */ + embedScholarshipBatch: { + methodKind: "unary"; + input: typeof EmbedScholarshipBatchRequestSchema; + output: typeof EmbedScholarshipBatchResponseSchema; + }, +}> = /*@__PURE__*/ + serviceDesc(file_rag_engine, 1); + diff --git a/frontend/src/hooks/data/index.ts b/frontend/src/hooks/data/index.ts deleted file mode 100644 index 486e0ae..0000000 --- a/frontend/src/hooks/data/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -// src/hooks/data/index.ts - -// Export core RPC hooks -export { useRPC, useRPCStream } from './useRPC'; -export type { RPCConfig, RPCState, RPCActions, UseRPCReturn } from './useRPC'; - -// TODO: EXPORT SPECIALIZED HOOKS HERE - -// TODO: EXPORT OTHER HOOKS HERE \ No newline at end of file diff --git a/frontend/src/hooks/data/useRPC.ts b/frontend/src/hooks/data/useRPC.ts deleted file mode 100644 index 591fa42..0000000 --- a/frontend/src/hooks/data/useRPC.ts +++ /dev/null @@ -1,407 +0,0 @@ -// src/hooks/data/useRPC.ts -/* DO NOT USE DIRECTLY!! IMPLEMENT METHODS IN useRPCHelpers.ts */ -import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; -import { MasterLog } from '@/services/LoggerService'; - -const Log = MasterLog.getSubLogger({ name: 'useRPC' }); - -/** - * Configuration options for RPC requests - */ -export interface RPCConfig { - /** Enable automatic retry on failure */ - retry?: boolean; - /** Number of retry attempts (default: 3) */ - retryAttempts?: number; - /** Delay between retries in ms (default: 1000) */ - retryDelay?: number; - /** Enable request cancellation on unmount */ - cancelOnUnmount?: boolean; - /** Custom error handler */ - onError?: (error: Error) => void; - /** Custom success handler */ - onSuccess?: (data: T) => void; -} - -/** - * State returned by useRPC hook - */ -export interface RPCState { - data: T | null; - error: Error | null; - loading: boolean; - isSuccess: boolean; - isError: boolean; -} - -/** - * Actions returned by useRPC hook - */ -export interface RPCActions { - execute: (request: TRequest) => Promise; - reset: () => void; - cancel: () => void; -} - -/** - * Return type combining state and actions - */ -export type UseRPCReturn = RPCState & RPCActions; - -const DEFAULT_CONFIG: Required = { - retry: false, - retryAttempts: 3, - retryDelay: 1000, - cancelOnUnmount: true, - onError: () => {}, - onSuccess: () => {}, -}; - -/** - * Generic hook for making RPC calls with automatic state management - * - * @template TRequest - Type of the request message - * @template TResponse - Type of the response message - * - * @param rpcMethod - Function that performs the RPC call - * @param config - Configuration options - * - * @example - * // Single request - * const { data, loading, error, execute } = useRPC( - * async (req: ProviderRequest) => { - * const client = RPCService.getResponseService(); - * return await client.getProvider(req); - * } - * ); - * - * @example - * // With retry logic - * const { data, loading, error, execute } = useRPC( - * async (req: MemberRequest) => { - * const client = RPCService.getResponseService(); - * return await client.getMember(req); - * }, - * { retry: true, retryAttempts: 3 } - * ); - */ -export function useRPC( - rpcMethod: (request: TRequest) => Promise, - config: RPCConfig = {} -): UseRPCReturn { - // Memoize config to prevent unnecessary re-renders - const mergedConfig = useMemo( - () => ({ ...DEFAULT_CONFIG, ...config }), - [config] - ); - - const [state, setState] = useState>({ - data: null, - error: null, - loading: false, - isSuccess: false, - isError: false, - }); - - const isMountedRef = useRef(true); - const abortControllerRef = useRef(null); - const requestIdRef = useRef(0); - - // Cleanup on unmount - useEffect(() => { - return () => { - isMountedRef.current = false; - if (mergedConfig.cancelOnUnmount && abortControllerRef.current) { - abortControllerRef.current.abort(); - } - }; - }, [mergedConfig.cancelOnUnmount]); - - /** - * Execute RPC call with retry logic - */ - const executeWithRetry = useCallback( - async (request: TRequest, attemptNumber = 1): Promise => { - try { - const response = await rpcMethod(request); - return response; - } catch (error) { - const isLastAttempt = attemptNumber >= mergedConfig.retryAttempts; - - if (mergedConfig.retry && !isLastAttempt) { - Log.warn('RPC call failed, retrying...', { - attempt: attemptNumber, - maxAttempts: mergedConfig.retryAttempts, - error: error instanceof Error ? error.message : String(error), - }); - - // Exponential backoff - await new Promise(resolve => - setTimeout(resolve, mergedConfig.retryDelay * attemptNumber) - ); - - return executeWithRetry(request, attemptNumber + 1); - } - - throw error; - } - }, - [rpcMethod, mergedConfig.retry, mergedConfig.retryAttempts, mergedConfig.retryDelay] - ); - - /** - * Execute the RPC call - */ - const execute = useCallback( - async (request: TRequest): Promise => { - const currentRequestId = ++requestIdRef.current; - - // Cancel any ongoing request - if (abortControllerRef.current) { - abortControllerRef.current.abort(); - } - - abortControllerRef.current = new AbortController(); - - setState({ - data: null, - error: null, - loading: true, - isSuccess: false, - isError: false, - }); - - try { - const response = await executeWithRetry(request); - - // Only update state if this is still the latest request and component is mounted - if (isMountedRef.current && currentRequestId === requestIdRef.current) { - setState({ - data: response, - error: null, - loading: false, - isSuccess: true, - isError: false, - }); - - if (response) { - mergedConfig.onSuccess(response); - } - } - - return response; - } catch (error) { - const errorObj = error instanceof Error ? error : new Error(String(error)); - - // Only update state if this is still the latest request and component is mounted - if (isMountedRef.current && currentRequestId === requestIdRef.current) { - setState({ - data: null, - error: errorObj, - loading: false, - isSuccess: false, - isError: true, - }); - - mergedConfig.onError(errorObj); - - Log.error('RPC call failed', { - error: errorObj.message, - stack: errorObj.stack, - }); - } - - return null; - } - }, - [executeWithRetry, mergedConfig] - ); - - /** - * Reset the state - */ - const reset = useCallback(() => { - setState({ - data: null, - error: null, - loading: false, - isSuccess: false, - isError: false, - }); - }, []); - - /** - * Cancel the ongoing request - */ - const cancel = useCallback(() => { - if (abortControllerRef.current) { - abortControllerRef.current.abort(); - Log.debug('RPC request cancelled'); - } - - if (isMountedRef.current) { - setState(prev => ({ - ...prev, - loading: false, - })); - } - }, []); - - return { - ...state, - execute, - reset, - cancel, - }; -} - -/** - * Hook for streaming RPC calls (server-side streaming) - * - * @template TRequest - Type of the request message - * @template TResponse - Type of the individual stream response message - * - * @param rpcStreamMethod - Function that performs the streaming RPC call - * @param config - Configuration options - * - * @example - * const { data, loading, error, execute } = useRPCStream( - * async function* (req: ProvidersRequest) { - * const client = RPCService.getResponseService(); - * for await (const provider of client.getProviders(req)) { - * yield provider; - * } - * } - * ); - */ -export function useRPCStream( - rpcStreamMethod: (request: TRequest) => AsyncIterable, - config: RPCConfig = {} -): UseRPCReturn { - // Memoize config to prevent unnecessary re-renders - const mergedConfig = useMemo( - () => ({ ...DEFAULT_CONFIG, ...config }), - [config] - ); - - const [state, setState] = useState>({ - data: null, - error: null, - loading: false, - isSuccess: false, - isError: false, - }); - - const isMountedRef = useRef(true); - const abortControllerRef = useRef(null); - const requestIdRef = useRef(0); - - useEffect(() => { - return () => { - isMountedRef.current = false; - if (mergedConfig.cancelOnUnmount && abortControllerRef.current) { - abortControllerRef.current.abort(); - } - }; - }, [mergedConfig.cancelOnUnmount]); - - const execute = useCallback( - async (request: TRequest): Promise => { - const currentRequestId = ++requestIdRef.current; - - if (abortControllerRef.current) { - abortControllerRef.current.abort(); - } - - abortControllerRef.current = new AbortController(); - - setState({ - data: null, - error: null, - loading: true, - isSuccess: false, - isError: false, - }); - - try { - const results: TResponse[] = []; - - for await (const response of rpcStreamMethod(request)) { - // Check if request was cancelled or component unmounted - if (!isMountedRef.current || currentRequestId !== requestIdRef.current) { - return null; - } - - results.push(response); - } - - if (isMountedRef.current && currentRequestId === requestIdRef.current) { - setState({ - data: results, - error: null, - loading: false, - isSuccess: true, - isError: false, - }); - - mergedConfig.onSuccess(results); - } - - return results; - } catch (error) { - const errorObj = error instanceof Error ? error : new Error(String(error)); - - if (isMountedRef.current && currentRequestId === requestIdRef.current) { - setState({ - data: null, - error: errorObj, - loading: false, - isSuccess: false, - isError: true, - }); - - mergedConfig.onError(errorObj); - - Log.error('RPC stream failed', { - error: errorObj.message, - stack: errorObj.stack, - }); - } - - return null; - } - }, - [rpcStreamMethod, mergedConfig] - ); - - const reset = useCallback(() => { - setState({ - data: null, - error: null, - loading: false, - isSuccess: false, - isError: false, - }); - }, []); - - const cancel = useCallback(() => { - if (abortControllerRef.current) { - abortControllerRef.current.abort(); - Log.debug('RPC stream cancelled'); - } - - if (isMountedRef.current) { - setState(prev => ({ - ...prev, - loading: false, - })); - } - }, []); - - return { - ...state, - execute, - reset, - cancel, - }; -} \ No newline at end of file diff --git a/frontend/src/hooks/data/useRPCHelpers.ts b/frontend/src/hooks/data/useRPCHelpers.ts deleted file mode 100644 index 400e55a..0000000 --- a/frontend/src/hooks/data/useRPCHelpers.ts +++ /dev/null @@ -1,124 +0,0 @@ -// src/hooks/data/useRPCHelpers.ts - - -/* UNCOMMENT once first RPC hooks's implemented in this file; use as logger. -import { MasterLog } from '@/services/LoggerService'; -const Log = MasterLog.getSubLogger({ name: 'useRPCHelpers' }); -*/ - - -/* EXAMPLE CODE BELOW - * Use the code below as a guide to create your own hooks. - ! REMEMBER TO UPDATE THE INDEX FILE WHEN YOU ADD NEW HOOKS - - -import { useRPC, useRPCStream, type RPCConfig, type UseRPCReturn } from './useRPC'; -import RPCService from '@/services/RPCService'; -import { - MemberRequest, - ProvidersRequest, - LoadMapRequest -} from '@/gen/protocol_pb'; -import type { - Provider, - Member, -} from '@/gen/protocol_pb'; -import type { MapData } from '@/gen/protocol_pb'; -*/ - - -/** - * Hook for fetching a single member by ID - * - * @example - * const { data: member, loading, error, execute } = useMember(); - * - * await execute(new MemberRequest({ memberId: "67890" })); - -export function useMember(config?: RPCConfig): UseRPCReturn { - return useRPC( - async (request: MemberRequest) => { - const client = RPCService.getResponseService(); - return await client.getMember(request); - }, - config - ); -} - */ - -/** - * Hook for streaming multiple providers - * - * @example - * const { data: providers, loading, error, execute } = useProviders(); - * - * await execute(new ProvidersRequest({ providerIds: ["1", "2", "3"] })); - -export function useProviders(config?: RPCConfig): UseRPCReturn { - return useRPCStream( - async function* (request: ProvidersRequest) { - const client = RPCService.getResponseService(); - for await (const provider of client.getProviders(request)) { - yield provider; - } - }, - config - ); -} -*/ - -/** - * Hook for loading map data - * - * @example - * const { data: mapData, loading, error, execute } = useMapData(); - * - * await execute(new LoadMapRequest({ - * h3Indices: ["abc", "def"], - * filters: {...}, - * loadProviders: true - * })); - -export function useLoadMap(config?: RPCConfig): UseRPCReturn { - return useRPC( - async (request: LoadMapRequest) => { - const client = RPCService.getResponseService(); - return await client.loadMap(request); - }, - config - ); -} - */ - - - - -/* Example usage: -import { MembersRequest } from "@/gen/protocol_pb"; -import { useMembers } from "@/hooks/data"; - - // Use the hook with automatic cleanup on unmount - const { - data: members, - loading, - error, - execute, - cancel - } = useMembers({ - cancelOnUnmount: true, - onError: (err) => { - console.error('Failed to fetch members:', err); - }, - }); - - // Fetch members when cell changes - useEffect(() => { - if (!cell) return; - - const request = new MembersRequest({ memberIds: cell.memberIds }); - execute(request); - - // Cleanup function: cancel request if cell changes or component unmounts - return () => cancel(); - }, [cell]); -*/ \ No newline at end of file diff --git a/frontend/src/hooks/data/useUpdateSignal.ts b/frontend/src/hooks/data/useUpdateSignal.ts deleted file mode 100644 index f145124..0000000 --- a/frontend/src/hooks/data/useUpdateSignal.ts +++ /dev/null @@ -1,46 +0,0 @@ -// src/hooks/data/useUpdateSignal.ts -import { ConnectionState, type UpdateSignalHookResult } from '@/types/updateSignal'; - -import { UpdateSignalManager } from '@/services/UpdateSignalManager'; - -import { useEffect, useRef, useState, useCallback } from 'react'; - -/** - * React hook for using update signal in components - * @param onUpdate Callback; executes when signal received - * @returns Current connection state - */ -export function useUpdateSignal( onUpdate: () => void ): UpdateSignalHookResult { - const manager = useRef(UpdateSignalManager.getInstance()); - const onUpdateRef = useRef(onUpdate); - - // Track connection state for UI updates - const [connectionState, setConnectionState] = useState( - manager.current.getConnectionState() - ); - - // Update ref onUpdate - useEffect(() => { - onUpdateRef.current = onUpdate; - }, [onUpdate]); - - // Stable callback using ref - const stableCallback = useCallback(() => { - onUpdateRef.current(); - }, []); - - // Subscription only 1x for component lifetime - useEffect(() => { - const instance = manager.current; - const unsubscribeUpdate = instance.subscribe(stableCallback); - const unsubscribeState = instance.onConnectionStateChange(setConnectionState); - - // Cleanup on unmount - return () => { - unsubscribeUpdate(); - unsubscribeState(); - }; - }, []); - - return { connectionState }; -} \ No newline at end of file diff --git a/frontend/src/hooks/state/index.ts b/frontend/src/hooks/state/index.ts deleted file mode 100644 index c67e4a3..0000000 --- a/frontend/src/hooks/state/index.ts +++ /dev/null @@ -1 +0,0 @@ -// src/hooks/state/index.ts \ No newline at end of file diff --git a/frontend/src/hooks/ui/index.ts b/frontend/src/hooks/ui/index.ts deleted file mode 100644 index e77ec33..0000000 --- a/frontend/src/hooks/ui/index.ts +++ /dev/null @@ -1 +0,0 @@ -// src/hooks/ui/index.ts \ No newline at end of file diff --git a/frontend/src/hooks/utils/index.ts b/frontend/src/hooks/utils/index.ts deleted file mode 100644 index 56e4f45..0000000 --- a/frontend/src/hooks/utils/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// src/hooks/utils/index.ts -/* '@/hooks/utils'; */ - -export { useDebounce } from './useDebounce'; \ No newline at end of file diff --git a/frontend/src/hooks/utils/useDebounce.ts b/frontend/src/hooks/utils/useDebounce.ts deleted file mode 100644 index efbe4df..0000000 --- a/frontend/src/hooks/utils/useDebounce.ts +++ /dev/null @@ -1,24 +0,0 @@ -// src/hooks/utils/useDebounce.ts -import { useState, useEffect } from 'react'; - -/** - * Custom hook for debouncing hex res & cluster updates - * @param value - The value to debounce - * @param delay - Debounce delay in milliseconds - * @returns Debounced value - */ -export function useDebounce(value: T, delay: number): T { - const [debouncedValue, setDebouncedValue] = useState(value); - - useEffect(() => { - const handler = setTimeout(() => { - setDebouncedValue(value); - }, delay); - - return () => { - clearTimeout(handler); - }; - }, [value, delay]); - - return debouncedValue; -} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx deleted file mode 100644 index 2c8a1f6..0000000 --- a/frontend/src/main.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import { Provider } from 'react-redux' -import { store } from '@/store' -import App from './App.tsx' -import './index.css' - -createRoot(document.getElementById('root')!).render( - - - - - , -) \ No newline at end of file diff --git a/electron/src/main/index.ts b/frontend/src/main/index.ts similarity index 97% rename from electron/src/main/index.ts rename to frontend/src/main/index.ts index b1befb4..ae79557 100644 --- a/electron/src/main/index.ts +++ b/frontend/src/main/index.ts @@ -30,7 +30,7 @@ function createWindow(): BrowserWindow { } app.whenReady().then(() => { - const mainWindow = createWindow(); + createWindow(); app.on('activate', function () { // Follow the macOS convention of re-creating a window in the app when there are no other windows open diff --git a/electron/src/preload/index.d.ts b/frontend/src/preload/index.d.ts similarity index 100% rename from electron/src/preload/index.d.ts rename to frontend/src/preload/index.d.ts diff --git a/electron/src/preload/index.ts b/frontend/src/preload/index.ts similarity index 100% rename from electron/src/preload/index.ts rename to frontend/src/preload/index.ts diff --git a/electron/src/renderer/index.html b/frontend/src/renderer/index.html similarity index 100% rename from electron/src/renderer/index.html rename to frontend/src/renderer/index.html diff --git a/frontend/src/renderer/src/App.tsx b/frontend/src/renderer/src/App.tsx new file mode 100644 index 0000000..eb3ff72 --- /dev/null +++ b/frontend/src/renderer/src/App.tsx @@ -0,0 +1,17 @@ +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' +import Landing from './pages/Landing' +import Dashboard from './pages/Dashboard' +import { HealthDashboard } from './pages/HealthDashboard' + +export default function App() { + return ( + + + } /> + } /> + } /> + } /> + + + ) +} diff --git a/frontend/src/api/client.ts b/frontend/src/renderer/src/api/client.ts similarity index 99% rename from frontend/src/api/client.ts rename to frontend/src/renderer/src/api/client.ts index 59a7b19..98bbc02 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/renderer/src/api/client.ts @@ -25,3 +25,4 @@ const transport = createConnectTransport({ */ export { transport, createClient }; + diff --git a/frontend/src/api/hooks.ts b/frontend/src/renderer/src/api/hooks.ts similarity index 99% rename from frontend/src/api/hooks.ts rename to frontend/src/renderer/src/api/hooks.ts index 016790e..3ac5934 100644 --- a/frontend/src/api/hooks.ts +++ b/frontend/src/renderer/src/api/hooks.ts @@ -41,3 +41,4 @@ export function useApiCall( return { execute, loading, error, data, reset }; } + diff --git a/frontend/src/components/navbar.tsx b/frontend/src/renderer/src/components/navbar.tsx similarity index 93% rename from frontend/src/components/navbar.tsx rename to frontend/src/renderer/src/components/navbar.tsx index f38d7d0..c894a3c 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/renderer/src/components/navbar.tsx @@ -8,4 +8,5 @@ const Navbar = () => { ; } -export default Navbar; \ No newline at end of file +export default Navbar; + diff --git a/frontend/src/components/ui/badge.tsx b/frontend/src/renderer/src/components/ui/badge.tsx similarity index 99% rename from frontend/src/components/ui/badge.tsx rename to frontend/src/renderer/src/components/ui/badge.tsx index 65c74c2..12230d5 100644 --- a/frontend/src/components/ui/badge.tsx +++ b/frontend/src/renderer/src/components/ui/badge.tsx @@ -36,3 +36,4 @@ function Badge({ className, variant, ...props }: BadgeProps) { } export { Badge, badgeVariants } + diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/renderer/src/components/ui/button.tsx similarity index 99% rename from frontend/src/components/ui/button.tsx rename to frontend/src/renderer/src/components/ui/button.tsx index 8c7cd04..75d3912 100644 --- a/frontend/src/components/ui/button.tsx +++ b/frontend/src/renderer/src/components/ui/button.tsx @@ -53,3 +53,4 @@ const Button = React.forwardRef( Button.displayName = "Button" export { Button, buttonVariants } + diff --git a/frontend/src/components/ui/card.tsx b/frontend/src/renderer/src/components/ui/card.tsx similarity index 99% rename from frontend/src/components/ui/card.tsx rename to frontend/src/renderer/src/components/ui/card.tsx index cabfbfc..d7ca945 100644 --- a/frontend/src/components/ui/card.tsx +++ b/frontend/src/renderer/src/components/ui/card.tsx @@ -74,3 +74,4 @@ const CardFooter = React.forwardRef< CardFooter.displayName = "CardFooter" export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } + diff --git a/frontend/src/components/ui/hover-card.tsx b/frontend/src/renderer/src/components/ui/hover-card.tsx similarity index 99% rename from frontend/src/components/ui/hover-card.tsx rename to frontend/src/renderer/src/components/ui/hover-card.tsx index 95643d9..425f9be 100644 --- a/frontend/src/components/ui/hover-card.tsx +++ b/frontend/src/renderer/src/components/ui/hover-card.tsx @@ -25,3 +25,4 @@ const HoverCardContent = React.forwardRef< HoverCardContent.displayName = HoverCardPrimitive.Content.displayName export { HoverCard, HoverCardTrigger, HoverCardContent } + diff --git a/frontend/src/components/ui/separator.tsx b/frontend/src/renderer/src/components/ui/separator.tsx similarity index 99% rename from frontend/src/components/ui/separator.tsx rename to frontend/src/renderer/src/components/ui/separator.tsx index 6d7f122..25cd7e4 100644 --- a/frontend/src/components/ui/separator.tsx +++ b/frontend/src/renderer/src/components/ui/separator.tsx @@ -27,3 +27,4 @@ const Separator = React.forwardRef< Separator.displayName = SeparatorPrimitive.Root.displayName export { Separator } + diff --git a/electron/src/renderer/src/hooks/data/index.ts b/frontend/src/renderer/src/hooks/data/index.ts similarity index 100% rename from electron/src/renderer/src/hooks/data/index.ts rename to frontend/src/renderer/src/hooks/data/index.ts diff --git a/electron/src/renderer/src/hooks/data/useRPC.ts b/frontend/src/renderer/src/hooks/data/useRPC.ts similarity index 100% rename from electron/src/renderer/src/hooks/data/useRPC.ts rename to frontend/src/renderer/src/hooks/data/useRPC.ts diff --git a/electron/src/renderer/src/hooks/data/useRPCHelpers.ts b/frontend/src/renderer/src/hooks/data/useRPCHelpers.ts similarity index 100% rename from electron/src/renderer/src/hooks/data/useRPCHelpers.ts rename to frontend/src/renderer/src/hooks/data/useRPCHelpers.ts diff --git a/electron/src/renderer/src/hooks/data/useUpdateSignal.ts b/frontend/src/renderer/src/hooks/data/useUpdateSignal.ts similarity index 100% rename from electron/src/renderer/src/hooks/data/useUpdateSignal.ts rename to frontend/src/renderer/src/hooks/data/useUpdateSignal.ts diff --git a/electron/src/renderer/src/hooks/state/index.ts b/frontend/src/renderer/src/hooks/state/index.ts similarity index 100% rename from electron/src/renderer/src/hooks/state/index.ts rename to frontend/src/renderer/src/hooks/state/index.ts diff --git a/electron/src/renderer/src/hooks/ui/index.ts b/frontend/src/renderer/src/hooks/ui/index.ts similarity index 100% rename from electron/src/renderer/src/hooks/ui/index.ts rename to frontend/src/renderer/src/hooks/ui/index.ts diff --git a/electron/src/renderer/src/hooks/utils/index.ts b/frontend/src/renderer/src/hooks/utils/index.ts similarity index 100% rename from electron/src/renderer/src/hooks/utils/index.ts rename to frontend/src/renderer/src/hooks/utils/index.ts diff --git a/electron/src/renderer/src/hooks/utils/useDebounce.ts b/frontend/src/renderer/src/hooks/utils/useDebounce.ts similarity index 100% rename from electron/src/renderer/src/hooks/utils/useDebounce.ts rename to frontend/src/renderer/src/hooks/utils/useDebounce.ts diff --git a/frontend/src/index.css b/frontend/src/renderer/src/index.css similarity index 99% rename from frontend/src/index.css rename to frontend/src/renderer/src/index.css index b32aa5b..f6fba78 100644 --- a/frontend/src/index.css +++ b/frontend/src/renderer/src/index.css @@ -67,4 +67,5 @@ @apply bg-background text-foreground; font-feature-settings: "rlig" 1, "calt" 1; } -} \ No newline at end of file +} + diff --git a/frontend/src/lib/utils.ts b/frontend/src/renderer/src/lib/utils.ts similarity index 99% rename from frontend/src/lib/utils.ts rename to frontend/src/renderer/src/lib/utils.ts index 90ee4df..2199204 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/renderer/src/lib/utils.ts @@ -7,3 +7,4 @@ import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } + diff --git a/electron/src/renderer/src/main.tsx b/frontend/src/renderer/src/main.tsx similarity index 50% rename from electron/src/renderer/src/main.tsx rename to frontend/src/renderer/src/main.tsx index 2a6077e..655cb52 100644 --- a/electron/src/renderer/src/main.tsx +++ b/frontend/src/renderer/src/main.tsx @@ -1,10 +1,14 @@ import React from 'react' import ReactDOM from 'react-dom/client' +import { Provider } from 'react-redux' +import { store } from './store' import App from './App' -import './style.css' +import './index.css' ReactDOM.createRoot(document.getElementById('root')!).render( - - + + + + , ) diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/renderer/src/pages/Dashboard.tsx similarity index 87% rename from frontend/src/pages/Dashboard.tsx rename to frontend/src/renderer/src/pages/Dashboard.tsx index 56fef03..0fef754 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/renderer/src/pages/Dashboard.tsx @@ -1,20 +1,10 @@ -import React, {useState, useEffect} from "react"; +import React from "react"; import { Separator } from "@/components/ui/separator"; import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card"; import { Button } from "@/components/ui/button"; import Navbar from "@/components/navbar"; -interface User { - id: Number; - name: String; - email: String; -}; - -interface DashboardProps { - -} - -const Dashboard: React.FC = (props) => { +const Dashboard: React.FC = () => { return (
@@ -52,4 +42,5 @@ const Dashboard: React.FC = (props) => { ); } -export default Dashboard; \ No newline at end of file +export default Dashboard; + diff --git a/frontend/src/pages/HealthDashboard.tsx b/frontend/src/renderer/src/pages/HealthDashboard.tsx similarity index 99% rename from frontend/src/pages/HealthDashboard.tsx rename to frontend/src/renderer/src/pages/HealthDashboard.tsx index 074ec57..b659210 100644 --- a/frontend/src/pages/HealthDashboard.tsx +++ b/frontend/src/renderer/src/pages/HealthDashboard.tsx @@ -99,4 +99,5 @@ export function HealthDashboard() { ); -} \ No newline at end of file +} + diff --git a/frontend/src/pages/Landing.tsx b/frontend/src/renderer/src/pages/Landing.tsx similarity index 93% rename from frontend/src/pages/Landing.tsx rename to frontend/src/renderer/src/pages/Landing.tsx index f99c854..ccf68a8 100644 --- a/frontend/src/pages/Landing.tsx +++ b/frontend/src/renderer/src/pages/Landing.tsx @@ -33,8 +33,8 @@ const Landing = () => {

-
โœ“ Vite + React
-
TypeScript
+
โœ“ Electron + Vite
+
Desktop App
โœ“ ShadCN UI
@@ -61,4 +61,5 @@ const Landing = () => { ); } -export default Landing; \ No newline at end of file +export default Landing; + diff --git a/frontend/src/store/healthSlice.ts b/frontend/src/renderer/src/store/healthSlice.ts similarity index 99% rename from frontend/src/store/healthSlice.ts rename to frontend/src/renderer/src/store/healthSlice.ts index 59d82b7..8ba8ab8 100644 --- a/frontend/src/store/healthSlice.ts +++ b/frontend/src/renderer/src/store/healthSlice.ts @@ -100,3 +100,4 @@ const healthSlice = createSlice({ export const { resetHealth } = healthSlice.actions; export default healthSlice.reducer; + diff --git a/electron/src/store/hooks.ts b/frontend/src/renderer/src/store/hooks.ts similarity index 61% rename from electron/src/store/hooks.ts rename to frontend/src/renderer/src/store/hooks.ts index 743b88a..28b6435 100644 --- a/electron/src/store/hooks.ts +++ b/frontend/src/renderer/src/store/hooks.ts @@ -1,10 +1,11 @@ /** - * Typed Redux hooks - * Use these instead of plain `useDispatch` and `useSelector` + * Redux Store Hooks + * Pre-typed hooks for use throughout the application */ import { useDispatch, useSelector } from 'react-redux'; import type { RootState, AppDispatch } from './index'; -// Use throughout the app instead of plain `useDispatch` and `useSelector` +// Use throughout your app instead of plain `useDispatch` and `useSelector` export const useAppDispatch = useDispatch.withTypes(); export const useAppSelector = useSelector.withTypes(); + diff --git a/electron/src/store/index.ts b/frontend/src/renderer/src/store/index.ts similarity index 92% rename from electron/src/store/index.ts rename to frontend/src/renderer/src/store/index.ts index 88f6f9a..6f50c8b 100644 --- a/electron/src/store/index.ts +++ b/frontend/src/renderer/src/store/index.ts @@ -2,7 +2,7 @@ * Redux Store Configuration */ import { configureStore } from '@reduxjs/toolkit'; -import healthReducer from '@/store/healthSlice'; +import healthReducer from './healthSlice'; export const store = configureStore({ reducer: { @@ -22,3 +22,4 @@ export const store = configureStore({ // Infer types from the store export type RootState = ReturnType; export type AppDispatch = typeof store.dispatch; + diff --git a/frontend/src/services/RPCService.ts b/frontend/src/services/RPCService.ts index d5cda3e..3748792 100644 --- a/frontend/src/services/RPCService.ts +++ b/frontend/src/services/RPCService.ts @@ -2,7 +2,8 @@ import { createConnectTransport } from "@connectrpc/connect-web"; import { createClient } from "@connectrpc/connect"; -import { Gateway } from "@/generated/api_gateway_connect"; +// Note: Generated proto clients will be imported here once `buf generate` is run +// import { Gateway } from "../generated/api_gateway_connect"; import { MasterLog } from "./LoggerService"; @@ -10,7 +11,7 @@ import { MasterLog } from "./LoggerService"; const Log = MasterLog.getSubLogger({ name: "RPCService" }); const BASE_URL = import.meta.env.VITE_GRPC_BASE_URL || "http://localhost:9090"; -const transport = createConnectTransport({ baseUrl: BASE_URL }); +export const transport = createConnectTransport({ baseUrl: BASE_URL }); interface ClientCache { gateway?: ReturnType; @@ -24,11 +25,12 @@ const clientCache: ClientCache = {}; export class RPCService { /** * @returns The Gateway client + * Note: Uncomment when proto code is generated */ static getGateway() { if (!clientCache.gateway) { - // @ts-expect-error - Generated service descriptor type mismatch with createClient - clientCache.gateway = createClient(Gateway, transport); + // Uncomment when proto code is generated: + // clientCache.gateway = createClient(Gateway, transport); Log.debug('Created new gRPC client for Gateway'); } return clientCache.gateway; diff --git a/frontend/src/services/UpdateSignalManager.ts b/frontend/src/services/UpdateSignalManager.ts index a888d5c..59bec07 100644 --- a/frontend/src/services/UpdateSignalManager.ts +++ b/frontend/src/services/UpdateSignalManager.ts @@ -1,7 +1,7 @@ // src/services/UpdateSignalManager.ts -import { ConnectionState, WEBSOCKET_URL } from '@/types/updateSignal'; +import { ConnectionState, WEBSOCKET_URL } from '@global/updateSignal'; -import { MasterLog } from '@/services/LoggerService'; +import { MasterLog } from '@services/LoggerService'; // Currently triggers update when "UPDATE" received via websocket diff --git a/electron/src/types/global/updateSignal.d.ts b/frontend/src/types/global/updateSignal.d.ts similarity index 100% rename from electron/src/types/global/updateSignal.d.ts rename to frontend/src/types/global/updateSignal.d.ts diff --git a/electron/src/types/renderer/vite-env.d.ts b/frontend/src/types/renderer/vite-env.d.ts similarity index 100% rename from electron/src/types/renderer/vite-env.d.ts rename to frontend/src/types/renderer/vite-env.d.ts diff --git a/frontend/src/types/updateSignal.ts b/frontend/src/types/updateSignal.ts deleted file mode 100644 index e475a44..0000000 --- a/frontend/src/types/updateSignal.ts +++ /dev/null @@ -1,16 +0,0 @@ -// src/types/updateSignal.ts - -export const ConnectionState = { - CONNECTING: 'connecting', - CONNECTED: 'connected', - DISCONNECTED: 'disconnected', - ERROR: 'error', -} as const; - -export type ConnectionState = typeof ConnectionState[keyof typeof ConnectionState]; - -export interface UpdateSignalHookResult { - connectionState: ConnectionState; -} - -export const WEBSOCKET_URL = import.meta.env.VITE_WEBSOCKET_URL || '/ws'; \ No newline at end of file diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 95a8e49..f38f135 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -2,8 +2,8 @@ export default { darkMode: ["class"], content: [ - "./index.html", - "./src/**/*.{js,ts,jsx,tsx}", + "./src/renderer/index.html", + "./src/renderer/src/**/*.{js,ts,jsx,tsx}", ], theme: { extend: { @@ -58,3 +58,4 @@ export default { }, plugins: [require("tailwindcss-animate")], } + diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json deleted file mode 100644 index ed28349..0000000 --- a/frontend/tsconfig.app.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Path aliases */ - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - }, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 1ffef60..6983ba4 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,7 +1,7 @@ { "files": [], "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } + { "path": "./tsconfig.node.json" }, + { "path": "./tsconfig.renderer.json" } ] } diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json index 7a77bab..fa62b41 100644 --- a/frontend/tsconfig.node.json +++ b/frontend/tsconfig.node.json @@ -1,26 +1,29 @@ { "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], + "composite": true, + "target": "ES2020", "module": "ESNext", - "types": [], - "skipLibCheck": true, - - /* Bundler mode */ + "lib": ["ES2020"], "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "erasableSyntaxOnly": true, "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "@services/*": ["src/services/*"], + "@global/*": ["src/types/global/*"], + "@renderer/*": ["src/renderer/src/*"], + "@hooks/*": ["src/renderer/src/hooks/*"], + "@main/*": ["src/main/*"], + "@preload/*": ["src/preload/*"] + } }, - "include": ["vite.config.ts"] + "include": ["src/main/**/*"], + "exclude": ["node_modules", "out"] } diff --git a/electron/tsconfig.renderer.json b/frontend/tsconfig.renderer.json similarity index 76% rename from electron/tsconfig.renderer.json rename to frontend/tsconfig.renderer.json index 5feee41..d348736 100644 --- a/electron/tsconfig.renderer.json +++ b/frontend/tsconfig.renderer.json @@ -16,11 +16,16 @@ "noFallthroughCasesInSwitch": true, "baseUrl": ".", "paths": { - "@/*": ["src/*"], + "@/*": ["src/renderer/src/*"], "@renderer/*": ["src/renderer/src/*"], "@services/*": ["src/services/*"], "@global/*": ["src/types/global/*"], "@hooks/*": ["src/renderer/src/hooks/*"], + "@components/*": ["src/renderer/src/components/*"], + "@lib/*": ["src/renderer/src/lib/*"], + "@store/*": ["src/renderer/src/store/*"], + "@api/*": ["src/renderer/src/api/*"], + "@pages/*": ["src/renderer/src/pages/*"], "@main/*": ["src/main/*"], "@preload/*": ["src/preload/*"] } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts deleted file mode 100644 index 8ed5d4b..0000000 --- a/frontend/vite.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import path from 'path' - -// https://vite.dev/config/ -export default defineConfig({ - plugins: [react()], - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, - server: { - port: 3000, - proxy: { - // Proxy gRPC-Web requests to backend - '/fi.gateway.v1.Gateway': { - target: 'http://localhost:50051', - changeOrigin: true, - }, - }, - }, -}) diff --git a/proto/rag_engine.proto b/proto/rag_engine.proto index cb224a9..9f9ddb0 100644 --- a/proto/rag_engine.proto +++ b/proto/rag_engine.proto @@ -129,3 +129,73 @@ message SearchResult { // Document metadata google.protobuf.Struct metadata = 4; } + +// ========================================= +// VectorDBService - declare RPC methods +// ========================================= +service VectorDBService { + // Initialize vector DB connection or collection + rpc Init(InitRequest) returns (InitResponse); + + // Embed a batch of scholarships and store them + rpc EmbedScholarshipBatch(EmbedScholarshipBatchRequest) returns (EmbedScholarshipBatchResponse); +} + +// ========================================= +// VectorDBService - Define RPC method requests and response schemas +// ========================================= + +message InitRequest { + string connection_string = 1; // e.g. "postgresql://user:pass@localhost/db" + string collection_name = 2; +} + +message InitResponse { + bool success = 1; + fi.common.v1.Error error = 2; +} + +message EmbedScholarshipBatchRequest { + repeated Scholarship scholarships = 1; // Example dataclass converted below +} + +message EmbedScholarshipBatchResponse { + int32 total_embedded = 1; + fi.common.v1.Error error = 2; +} + +//may change +message Document { + string document_id = 1; + string content = 2; + google.protobuf.Struct metadata = 3; +} + +message Scholarship { + // Unique scholarship identifier + int32 id = 1; + + // Scholarship name + string name = 2; + + // Scholarship description or summary + string description = 3; + + // Minimum GPA required (e.g. 3.5) + double min_gpa = 4; + + // Eligible majors (e.g. "Computer Science", "Engineering") + repeated string eligible_majors = 5; + + // Citizenship requirement (optional, can be null) + string citizenship_required = 6; + + // Location requirement or region (optional) + string location = 7; + + // Award amount or range, kept as a string for flexibility + string award_amount = 8; + + // Keywords for semantic search / classification + repeated string keywords = 9; +} \ No newline at end of file diff --git a/scripts/db_utils.sh b/scripts/db_utils.sh new file mode 100755 index 0000000..f5bc4d0 --- /dev/null +++ b/scripts/db_utils.sh @@ -0,0 +1,338 @@ +#!/bin/bash +# Database utility script for FiApply PostgreSQL + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Default values +CONTAINER_NAME="fi-postgres" +DB_NAME="fiapply" +DB_USER="fiapply_user" +DB_PASSWORD="fiapply_password" + +# Helper functions +print_success() { + echo -e "${GREEN}โœ“${NC} $1" +} + +print_error() { + echo -e "${RED}โœ—${NC} $1" +} + +print_info() { + echo -e "${BLUE}โ„น${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}โš ${NC} $1" +} + +# Check if container is running +check_container() { + if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + print_error "Container ${CONTAINER_NAME} is not running" + print_info "Start it with: docker-compose up postgres" + exit 1 + fi +} + +# Connect to database +connect() { + check_container + print_info "Connecting to database..." + docker exec -it ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} +} + +# Run SQL file +run_sql_file() { + if [ -z "$1" ]; then + print_error "Usage: $0 run-sql " + exit 1 + fi + + check_container + + if [ ! -f "$1" ]; then + print_error "File not found: $1" + exit 1 + fi + + print_info "Running SQL file: $1" + docker exec -i ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} < "$1" + print_success "SQL file executed successfully" +} + +# Backup database +backup() { + check_container + + BACKUP_FILE="backup_$(date +%Y%m%d_%H%M%S).sql" + print_info "Creating backup: ${BACKUP_FILE}" + + docker exec ${CONTAINER_NAME} pg_dump -U ${DB_USER} ${DB_NAME} > ${BACKUP_FILE} + print_success "Backup created: ${BACKUP_FILE}" +} + +# Backup schema only +backup_schema() { + check_container + + BACKUP_FILE="schema_$(date +%Y%m%d_%H%M%S).sql" + print_info "Creating schema backup: ${BACKUP_FILE}" + + docker exec ${CONTAINER_NAME} pg_dump -U ${DB_USER} --schema-only ${DB_NAME} > ${BACKUP_FILE} + print_success "Schema backup created: ${BACKUP_FILE}" +} + +# Restore database +restore() { + if [ -z "$1" ]; then + print_error "Usage: $0 restore " + exit 1 + fi + + check_container + + if [ ! -f "$1" ]; then + print_error "Backup file not found: $1" + exit 1 + fi + + print_warning "This will overwrite the current database. Are you sure? (yes/no)" + read -r confirmation + + if [ "$confirmation" != "yes" ]; then + print_info "Restore cancelled" + exit 0 + fi + + print_info "Restoring from backup: $1" + docker exec -i ${CONTAINER_NAME} psql -U ${DB_USER} ${DB_NAME} < "$1" + print_success "Database restored successfully" +} + +# Reset database (drop and recreate) +reset() { + check_container + + print_warning "This will delete ALL data and recreate the database. Are you sure? (yes/no)" + read -r confirmation + + if [ "$confirmation" != "yes" ]; then + print_info "Reset cancelled" + exit 0 + fi + + print_info "Resetting database..." + + # Drop and recreate database + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d postgres -c "DROP DATABASE IF EXISTS ${DB_NAME};" + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d postgres -c "CREATE DATABASE ${DB_NAME};" + + # Run initialization scripts + print_info "Running initialization scripts..." + docker exec -i ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} < init.sql + docker exec -i ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} < fiapply.sql + + print_success "Database reset complete" +} + +# Show database stats +stats() { + check_container + + print_info "Database Statistics" + echo "" + + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} << 'EOF' +-- Database size +SELECT + pg_size_pretty(pg_database_size(current_database())) as database_size; + +-- Table sizes +SELECT + schemaname, + tablename, + pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size, + pg_total_relation_size(schemaname||'.'||tablename) as size_bytes +FROM pg_tables +WHERE schemaname = 'public' +ORDER BY size_bytes DESC +LIMIT 10; + +-- Row counts +SELECT + schemaname, + tablename, + n_live_tup as row_count +FROM pg_stat_user_tables +ORDER BY n_live_tup DESC; +EOF +} + +# Check health +health() { + check_container + + print_info "Checking database health..." + + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} << 'EOF' +-- Health check +SELECT * FROM health_check; + +-- Extensions +SELECT * FROM pg_extension WHERE extname IN ('vector', 'pg_trgm', 'pg_stat_statements'); + +-- Connection info +SELECT + count(*) as active_connections, + max_conn.setting as max_connections +FROM pg_stat_activity, + (SELECT setting FROM pg_settings WHERE name = 'max_connections') max_conn +GROUP BY max_conn.setting; +EOF + + print_success "Database is healthy" +} + +# List tables +list_tables() { + check_container + + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} -c "\dt" +} + +# List indexes +list_indexes() { + check_container + + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} -c "\di" +} + +# Show slow queries +slow_queries() { + check_container + + print_info "Top 10 slowest queries" + + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} << 'EOF' +SELECT + substring(query, 1, 60) as query_snippet, + calls, + round(mean_exec_time::numeric, 2) as avg_time_ms, + round(total_exec_time::numeric, 2) as total_time_ms +FROM pg_stat_statements +ORDER BY mean_exec_time DESC +LIMIT 10; +EOF +} + +# Vacuum database +vacuum() { + check_container + + print_info "Running VACUUM ANALYZE..." + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} -c "VACUUM ANALYZE;" + print_success "VACUUM ANALYZE complete" +} + +# Refresh materialized views +refresh_views() { + check_container + + print_info "Refreshing materialized views..." + docker exec ${CONTAINER_NAME} psql -U ${DB_USER} -d ${DB_NAME} -c "REFRESH MATERIALIZED VIEW opportunity_stats;" + print_success "Materialized views refreshed" +} + +# Show help +show_help() { + cat << EOF +FiApply PostgreSQL Utility Script + +Usage: $0 [args] + +Commands: + connect Connect to the database (psql shell) + run-sql Run a SQL file + backup Create a full database backup + backup-schema Create a schema-only backup + restore Restore database from backup + reset Reset database (drop and recreate) + stats Show database statistics + health Check database health + list-tables List all tables + list-indexes List all indexes + slow-queries Show slowest queries + vacuum Run VACUUM ANALYZE + refresh-views Refresh materialized views + help Show this help message + +Examples: + $0 connect + $0 backup + $0 restore backup_20231010_120000.sql + $0 run-sql migrations/add_column.sql + $0 stats + +EOF +} + +# Main script +case "$1" in + connect) + connect + ;; + run-sql) + run_sql_file "$2" + ;; + backup) + backup + ;; + backup-schema) + backup_schema + ;; + restore) + restore "$2" + ;; + reset) + reset + ;; + stats) + stats + ;; + health) + health + ;; + list-tables) + list_tables + ;; + list-indexes) + list_indexes + ;; + slow-queries) + slow_queries + ;; + vacuum) + vacuum + ;; + refresh-views) + refresh_views + ;; + help|--help|-h|"") + show_help + ;; + *) + print_error "Unknown command: $1" + echo "" + show_help + exit 1 + ;; +esac +