diff --git a/.gitea/workflows/build-gateway.yml b/.gitea/workflows/build-gateway.yml new file mode 100644 index 0000000..868f992 --- /dev/null +++ b/.gitea/workflows/build-gateway.yml @@ -0,0 +1,166 @@ +name: Build Gateway + +on: + workflow_dispatch: + push: + tags: + - 'v*.*.*' + +env: + REGISTRY: ${{ gitea.server_url }} + IMAGE_NAME: ${{ gitea.repository_owner }}/fictionarchive-api + +jobs: + build-subgraphs: + runs-on: ubuntu-latest + strategy: + matrix: + service: + - name: novel-service + project: FictionArchive.Service.NovelService + subgraph: Novel + - name: translation-service + project: FictionArchive.Service.TranslationService + subgraph: Translation + - name: scheduler-service + project: FictionArchive.Service.SchedulerService + subgraph: Scheduler + - name: user-service + project: FictionArchive.Service.UserService + subgraph: User + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + - name: Install Fusion CLI + run: dotnet tool install -g HotChocolate.Fusion.CommandLine + + - name: Add .NET tools to PATH + run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH + + - name: Restore dependencies + run: dotnet restore ${{ matrix.service.project }}/${{ matrix.service.project }}.csproj + + - name: Build + run: dotnet build ${{ matrix.service.project }}/${{ matrix.service.project }}.csproj -c Release --no-restore + + - name: Export schema + run: | + dotnet run -c Release --no-launch-profile \ + --project ${{ matrix.service.project }}/${{ matrix.service.project }}.csproj \ + -- schema export --output schema.graphql + + - name: Pack subgraph + run: fusion subgraph pack -w ${{ matrix.service.project }} + + - name: Upload subgraph package + uses: christopherhx/gitea-upload-artifact@v4 + with: + name: ${{ matrix.service.name }}-subgraph + path: ${{ matrix.service.project }}/*.fsp + retention-days: 30 + + build-gateway: + runs-on: ubuntu-latest + needs: build-subgraphs + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + - name: Install Fusion CLI + run: dotnet tool install -g HotChocolate.Fusion.CommandLine + + - name: Add .NET tools to PATH + run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH + + - name: Create subgraphs directory + run: mkdir -p subgraphs + + - name: Download Novel Service subgraph + uses: christopherhx/gitea-download-artifact@v4 + with: + name: novel-service-subgraph + path: subgraphs/novel + + - name: Download Translation Service subgraph + uses: christopherhx/gitea-download-artifact@v4 + with: + name: translation-service-subgraph + path: subgraphs/translation + + - name: Download Scheduler Service subgraph + uses: christopherhx/gitea-download-artifact@v4 + with: + name: scheduler-service-subgraph + path: subgraphs/scheduler + + - name: Download User Service subgraph + uses: christopherhx/gitea-download-artifact@v4 + with: + name: user-service-subgraph + path: subgraphs/user + + - name: Configure subgraph URLs for Docker + run: | + for fsp in subgraphs/*/*.fsp; do + if [ -f "$fsp" ]; then + dir=$(dirname "$fsp") + name=$(basename "$dir") + url="http://${name}-service:8080/graphql" + echo "Setting $name URL to $url" + fusion subgraph config set http --url "$url" -c "$fsp" + fi + done + + - name: Compose gateway + run: | + cd FictionArchive.API + rm -f gateway.fgp + for fsp in ../subgraphs/*/*.fsp; do + if [ -f "$fsp" ]; then + echo "Composing: $fsp" + fusion compose -p gateway.fgp -s "$fsp" + fi + done + + - name: Restore dependencies + run: dotnet restore FictionArchive.API/FictionArchive.API.csproj + + - name: Build gateway + run: dotnet build FictionArchive.API/FictionArchive.API.csproj -c Release --no-restore -p:SkipFusionBuild=true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract registry hostname + id: registry + run: echo "HOST=$(echo '${{ gitea.server_url }}' | sed 's|https\?://||')" >> $GITHUB_OUTPUT + + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: FictionArchive.API/Dockerfile + push: true + tags: | + ${{ steps.registry.outputs.HOST }}/${{ env.IMAGE_NAME }}:latest + ${{ steps.registry.outputs.HOST }}/${{ env.IMAGE_NAME }}:${{ gitea.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..ed698a9 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,74 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build-backend: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + + - name: Restore dependencies + run: dotnet restore FictionArchive.sln + + - name: Build solution + run: dotnet build FictionArchive.sln --configuration Release --no-restore /p:SkipFusionBuild=true + + - name: Run tests + run: | + dotnet test FictionArchive.sln --configuration Release --no-build --verbosity normal \ + --logger "trx;LogFileName=test-results.trx" \ + --collect:"XPlat Code Coverage" \ + --results-directory ./TestResults + + - name: Upload test results + uses: christopherhx/gitea-upload-artifact@v4 + if: always() + with: + name: test-results + path: ./TestResults/**/*.trx + retention-days: 30 + + - name: Upload coverage results + uses: christopherhx/gitea-upload-artifact@v4 + if: always() + with: + name: coverage-results + path: ./TestResults/**/coverage.cobertura.xml + retention-days: 30 + + build-frontend: + runs-on: ubuntu-latest + defaults: + run: + working-directory: fictionarchive-web + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v6.0.0 + with: + node-version: '20' + package-manager-cache: false + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint + + - name: Build + run: npm run build diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..b71bd27 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,104 @@ +name: Release + +on: + push: + tags: + - 'v*.*.*' + +env: + REGISTRY: ${{ gitea.server_url }} + IMAGE_PREFIX: ${{ gitea.repository_owner }}/fictionarchive + +jobs: + build-and-push: + runs-on: ubuntu-latest + strategy: + matrix: + service: + - name: novel-service + dockerfile: FictionArchive.Service.NovelService/Dockerfile + - name: user-service + dockerfile: FictionArchive.Service.UserService/Dockerfile + - name: translation-service + dockerfile: FictionArchive.Service.TranslationService/Dockerfile + - name: file-service + dockerfile: FictionArchive.Service.FileService/Dockerfile + - name: scheduler-service + dockerfile: FictionArchive.Service.SchedulerService/Dockerfile + - name: authentication-service + dockerfile: FictionArchive.Service.AuthenticationService/Dockerfile + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT + + - name: Extract registry hostname + id: registry + run: echo "HOST=$(echo '${{ gitea.server_url }}' | sed 's|https\?://||')" >> $GITHUB_OUTPUT + + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.service.dockerfile }} + push: true + tags: | + ${{ steps.registry.outputs.HOST }}/${{ env.IMAGE_PREFIX }}-${{ matrix.service.name }}:${{ steps.version.outputs.VERSION }} + ${{ steps.registry.outputs.HOST }}/${{ env.IMAGE_PREFIX }}-${{ matrix.service.name }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + build-frontend: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT + + - name: Extract registry hostname + id: registry + run: echo "HOST=$(echo '${{ gitea.server_url }}' | sed 's|https\?://||')" >> $GITHUB_OUTPUT + + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Build and push frontend Docker image + uses: docker/build-push-action@v6 + with: + context: ./fictionarchive-web + file: fictionarchive-web/Dockerfile + push: true + build-args: | + VITE_GRAPHQL_URI=${{ vars.VITE_GRAPHQL_URI }} + VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }} + VITE_OIDC_CLIENT_ID=${{ vars.VITE_OIDC_CLIENT_ID }} + VITE_OIDC_REDIRECT_URI=${{ vars.VITE_OIDC_REDIRECT_URI }} + VITE_OIDC_POST_LOGOUT_REDIRECT_URI=${{ vars.VITE_OIDC_POST_LOGOUT_REDIRECT_URI }} + tags: | + ${{ steps.registry.outputs.HOST }}/${{ env.IMAGE_PREFIX }}-frontend:${{ steps.version.outputs.VERSION }} + ${{ steps.registry.outputs.HOST }}/${{ env.IMAGE_PREFIX }}-frontend:latest + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/AGENTS.md b/Documentation/AGENTS.md similarity index 100% rename from AGENTS.md rename to Documentation/AGENTS.md diff --git a/Documentation/ARCHITECTURE.md b/Documentation/ARCHITECTURE.md new file mode 100644 index 0000000..6cf034b --- /dev/null +++ b/Documentation/ARCHITECTURE.md @@ -0,0 +1,405 @@ +# FictionArchive Architecture Overview + +## High-Level Architecture + +``` +┌────────────────────────────────────────────────────────────────┐ +│ React 19 Frontend │ +│ (Apollo Client, TailwindCSS, OIDC Auth) │ +└───────────────────────────┬────────────────────────────────────┘ + │ GraphQL + ▼ +┌────────────────────────────────────────────────────────────────┐ +│ Hot Chocolate Fusion Gateway │ +│ (FictionArchive.API) │ +└──────┬────────┬────────┬────────┬────────┬─────────────────────┘ + │ │ │ │ │ + ▼ ▼ ▼ ▼ ▼ +┌──────────┐┌──────────┐┌───────────┐┌──────────┐┌──────────────┐ +│ Novel ││ User ││Translation││Scheduler ││ File │ +│ Service ││ Service ││ Service ││ Service ││ Service │ +└────┬─────┘└────┬─────┘└─────┬─────┘└────┬─────┘└──────┬───────┘ + │ │ │ │ │ + └───────────┴────────────┴───────────┴─────────────┘ + │ + ┌────────┴────────┐ + │ RabbitMQ │ + │ (Event Bus) │ + └─────────────────┘ + │ + ┌────────┴────────┐ + │ PostgreSQL │ + │ (per service) │ + └─────────────────┘ +``` + +## Technology Stack + +| Layer | Technology | Version | +|-------|------------|---------| +| Runtime | .NET | 8.0 | +| GraphQL | Hot Chocolate / Fusion | 13+ | +| Database | PostgreSQL | 12+ | +| ORM | Entity Framework Core | 8.0 | +| Message Broker | RabbitMQ | 3.12+ | +| Job Scheduler | Quartz.NET | Latest | +| Object Storage | AWS S3 / Garage | - | +| Date/Time | NodaTime | Latest | +| Frontend | React | 19.2 | +| Frontend Build | Vite | 7.2 | +| GraphQL Client | Apollo Client | 4.0 | +| Auth | OIDC Client TS | 3.4 | +| Styling | TailwindCSS | 3.4 | +| UI Components | Radix UI | Latest | + +## Project Structure + +``` +FictionArchive.sln +├── FictionArchive.Common # Shared enums and extensions +├── FictionArchive.API # GraphQL Fusion Gateway +├── FictionArchive.Service.Shared # Shared infrastructure +├── FictionArchive.Service.NovelService +├── FictionArchive.Service.UserService +├── FictionArchive.Service.TranslationService +├── FictionArchive.Service.FileService +├── FictionArchive.Service.SchedulerService +├── FictionArchive.Service.AuthenticationService +├── FictionArchive.Service.NovelService.Tests +└── fictionarchive-web # React frontend +``` + +## Services + +### FictionArchive.API - GraphQL Fusion Gateway + +- **Role**: Single entry point for all GraphQL queries +- **Port**: 5001 (HTTPS) +- **Endpoints**: + - `/graphql` - GraphQL endpoint + - `/healthz` - Health check +- **Responsibilities**: + - Compose GraphQL schemas from all subgraphs + - Route queries to appropriate services + - CORS policy management + +### FictionArchive.Service.NovelService + +- **Role**: Novel/fiction content management +- **Port**: 8081 (HTTPS) +- **Database**: `FictionArchive_NovelService` +- **GraphQL Operations**: + - `GetNovels` - Paginated, filterable novel listing + - `ImportNovel` - Trigger novel import + - `FetchChapterContents` - Fetch chapter content +- **Models**: Novel, Chapter, Source, NovelTag, Image, LocalizationKey +- **External Integration**: Novelpia adapter +- **Events Published**: `TranslationRequestCreatedEvent`, `FileUploadRequestCreatedEvent` +- **Events Subscribed**: `TranslationRequestCompletedEvent`, `NovelUpdateRequestedEvent`, `ChapterPullRequestedEvent`, `FileUploadRequestStatusUpdateEvent` + +### FictionArchive.Service.UserService + +- **Role**: User identity and profile management +- **Port**: 8081 (HTTPS) +- **Database**: `FictionArchive_UserService` +- **Models**: User (with OAuth provider linking) +- **Events Subscribed**: `AuthUserAddedEvent` + +### FictionArchive.Service.TranslationService + +- **Role**: Text translation orchestration +- **Port**: 8081 (HTTPS) +- **Database**: `FictionArchive_TranslationService` +- **External Integration**: DeepL API +- **Models**: TranslationRequest +- **Events Published**: `TranslationRequestCompletedEvent` +- **Events Subscribed**: `TranslationRequestCreatedEvent` + +### FictionArchive.Service.FileService + +- **Role**: File storage and S3 proxy +- **Port**: 8080 (HTTP) +- **Protocol**: REST only (not GraphQL) +- **Endpoints**: `GET /api/{*path}` - S3 file proxy +- **External Integration**: S3-compatible storage (AWS S3 / Garage) +- **Events Published**: `FileUploadRequestStatusUpdateEvent` +- **Events Subscribed**: `FileUploadRequestCreatedEvent` + +### FictionArchive.Service.SchedulerService + +- **Role**: Job scheduling and automation +- **Port**: 8081 (HTTPS) +- **Database**: `FictionArchive_SchedulerService` +- **Scheduler**: Quartz.NET with persistent job store +- **GraphQL Operations**: `ScheduleEventJob`, `GetScheduledJobs` +- **Models**: SchedulerJob, EventJobTemplate + +### FictionArchive.Service.AuthenticationService + +- **Role**: OAuth/OIDC webhook receiver +- **Port**: 8080 (HTTP) +- **Protocol**: REST only +- **Endpoints**: `POST /api/AuthenticationWebhook/UserRegistered` +- **Events Published**: `AuthUserAddedEvent` +- **No Database** - Stateless webhook handler + +## Communication Patterns + +### GraphQL Federation + +- Hot Chocolate Fusion Gateway composes subgraph schemas +- Schema export automated via `build_gateway.py` +- Each service defines its own Query/Mutation types + +### Event-Driven Architecture (RabbitMQ) + +- Direct exchange: `fiction-archive-event-bus` +- Per-service queues based on `ClientIdentifier` +- Routing key = event class name +- Headers: `X-Created-At`, `X-Event-Id` +- NodaTime JSON serialization + +### Event Flow Examples + +**Novel Import:** +``` +1. Frontend → importNovel mutation +2. NovelService publishes NovelUpdateRequestedEvent +3. NovelUpdateRequestedEventHandler processes +4. Fetches metadata via NovelpiaAdapter +5. Publishes FileUploadRequestCreatedEvent (for cover) +6. FileService uploads to S3 +7. FileService publishes FileUploadRequestStatusUpdateEvent +8. NovelService updates image path +``` + +**Translation:** +``` +1. NovelService publishes TranslationRequestCreatedEvent +2. TranslationService translates via DeepL +3. TranslationService publishes TranslationRequestCompletedEvent +4. NovelService updates chapter translation +``` + +## Data Storage + +### Database Pattern +- Database per service (PostgreSQL) +- Connection string format: `Host=localhost;Database=FictionArchive_{ServiceName};...` +- Auto-migration on startup via `dbContext.UpdateDatabase()` + +### Audit Trail +- `AuditInterceptor` auto-sets `CreatedTime` and `LastUpdatedTime` +- `IAuditable` interface with NodaTime `Instant` fields +- `BaseEntity` abstract base class + +### Object Storage +- S3-compatible (AWS S3 or Garage) +- Path-style URLs for Garage compatibility +- Proxied through FileService + +## Frontend Architecture + +### Structure +``` +fictionarchive-web/ +├── src/ +│ ├── auth/ # OIDC authentication +│ ├── components/ # React components +│ │ └── ui/ # Radix-based primitives +│ ├── pages/ # Route pages +│ ├── layouts/ # Layout components +│ ├── graphql/ # GraphQL queries +│ ├── __generated__/ # Codegen output +│ └── lib/ # Utilities +└── codegen.ts # GraphQL Codegen config +``` + +### Authentication +- OIDC via `oidc-client-ts` +- Environment variables for configuration +- `useAuth` hook for state access + +### State Management +- Apollo Client for GraphQL state +- React Context for auth state + +## Infrastructure + +### Docker +- Multi-stage builds +- Base: `mcr.microsoft.com/dotnet/aspnet:8.0` +- Non-root user for security +- Ports: 8080 (HTTP) or 8081 (HTTPS) + +### Health Checks +- All services expose `/healthz` + +### Configuration +- `appsettings.json` - Default settings +- `appsettings.Development.json` - Dev overrides +- `appsettings.Local.json` - Local secrets (not committed) + +--- + +# Improvement Recommendations + +## Critical + +### 1. Event Bus - No Dead Letter Queue or Retry Logic +**Location**: `FictionArchive.Service.Shared/Services/EventBus/Implementations/RabbitMQEventBus.cs:126-133` + +**Issue**: Events are always ACK'd even on failure. No DLQ configuration for poison messages. Failed events are lost forever. + +**Recommendation**: Implement retry with exponential backoff, dead-letter exchange, and poison message handling. + +```csharp +// Example: Add retry and DLQ +catch (Exception e) +{ + _logger.LogError(e, "Error handling event"); + if (retryCount < maxRetries) + { + await channel.BasicNackAsync(@event.DeliveryTag, false, true); // requeue + } + else + { + // Send to DLQ + await channel.BasicNackAsync(@event.DeliveryTag, false, false); + } +} +``` + +### 2. CORS Configuration is Insecure +**Location**: `FictionArchive.API/Program.cs:24-33` + +**Issue**: `AllowAnyOrigin()` allows requests from any domain, unsuitable for production. + +**Recommendation**: Configure specific allowed origins via appsettings: +```csharp +builder.Services.AddCors(options => +{ + options.AddPolicy("Production", policy => + { + policy.WithOrigins(builder.Configuration.GetSection("Cors:AllowedOrigins").Get()) + .AllowAnyMethod() + .AllowAnyHeader(); + }); +}); +``` + +### 3. Auto-Migration on Startup +**Location**: `FictionArchive.Service.Shared/Services/Database/FictionArchiveDbContext.cs:23-38` + +**Issue**: Running migrations at startup can cause race conditions with multiple instances and potential data corruption during rolling deployments. + +**Recommendation**: Use a migration job, init container, or CLI tool instead of startup code. + +## Important + +### 4. No Circuit Breaker Pattern +**Issue**: External service calls (DeepL, Novelpia, S3) lack resilience patterns. + +**Recommendation**: Add Polly for circuit breaker, retry, and timeout policies: +```csharp +builder.Services.AddHttpClient() + .AddPolicyHandler(GetRetryPolicy()) + .AddPolicyHandler(GetCircuitBreakerPolicy()); +``` + +### 5. Missing Request Validation/Rate Limiting +**Issue**: No visible rate limiting on GraphQL mutations. `ImportNovel` could be abused. + +**Recommendation**: Add rate limiting middleware and input validation. + +### 6. Hardcoded Exchange Name +**Location**: `RabbitMQEventBus.cs:24` + +**Issue**: `fiction-archive-event-bus` is hardcoded. + +**Recommendation**: Move to configuration for environment flexibility. + +### 7. No Distributed Tracing +**Issue**: Event correlation exists (`X-Event-Id` header) but not integrated with tracing. + +**Recommendation**: Add OpenTelemetry for end-to-end request tracing across services. + +### 8. Singleton AuditInterceptor +**Location**: `FictionArchiveDbContext.cs:20` + +**Issue**: `new AuditInterceptor()` created per DbContext instance. + +**Recommendation**: Register as singleton in DI and inject. + +## Minor / Code Quality + +### 9. Limited Test Coverage +**Issue**: Only `NovelService.Tests` exists. No integration tests for event handlers. + +**Recommendation**: Add unit and integration tests for each service, especially event handlers. + +### 10. Inconsistent Port Configuration +**Issue**: Some services use 8080 (HTTP), others 8081 (HTTPS). + +**Recommendation**: Standardize on HTTPS with proper cert management. + +### 11. No API Versioning +**Issue**: GraphQL schemas have no versioning strategy. + +**Recommendation**: Consider schema versioning or deprecation annotations for breaking changes. + +### 12. Frontend - No Error Boundary +**Issue**: React app lacks error boundaries for graceful failure handling. + +**Recommendation**: Add React Error Boundaries around routes. + +### 13. Missing Health Check Depth +**Issue**: Health checks only verify service is running, not dependencies. + +**Recommendation**: Add database, RabbitMQ, and S3 health checks: +```csharp +builder.Services.AddHealthChecks() + .AddNpgSql(connectionString) + .AddRabbitMQ() + .AddS3(options => { }); +``` + +### 14. Synchronous File Operations in Event Handlers +**Issue**: File uploads may block event handling thread for large files. + +**Recommendation**: Consider async streaming for large files. + +## Architectural Suggestions + +### 15. Consider Outbox Pattern +**Issue**: Publishing events and saving to DB aren't transactional, could lead to inconsistent state. + +**Recommendation**: Implement transactional outbox pattern for guaranteed delivery: +``` +1. Save entity + outbox message in same transaction +2. Background worker publishes from outbox +3. Delete outbox message after successful publish +``` + +### 16. Gateway Schema Build Process +**Issue**: Python script (`build_gateway.py`) for schema composition requires manual execution. + +**Recommendation**: Integrate into CI/CD pipeline or consider runtime schema polling. + +### 17. Secret Management +**Issue**: Credentials in appsettings files. + +**Recommendation**: Use Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, or similar secret management solution. + +--- + +## Key Files Reference + +| File | Purpose | +|------|---------| +| `FictionArchive.API/Program.cs` | Gateway setup | +| `FictionArchive.API/build_gateway.py` | Schema composition script | +| `FictionArchive.Service.Shared/Services/EventBus/` | Event bus implementation | +| `FictionArchive.Service.Shared/Extensions/` | Service registration helpers | +| `FictionArchive.Service.Shared/Services/Database/` | DB infrastructure | +| `fictionarchive-web/src/auth/AuthContext.tsx` | Frontend auth state | diff --git a/Documentation/CICD.md b/Documentation/CICD.md new file mode 100644 index 0000000..d42b958 --- /dev/null +++ b/Documentation/CICD.md @@ -0,0 +1,297 @@ +# CI/CD Configuration + +This document describes the CI/CD pipeline configuration for FictionArchive using Gitea Actions. + +## Workflows Overview + +| Workflow | File | Trigger | Purpose | +|----------|------|---------|---------| +| CI | `build.yml` | Push/PR to master | Build and test all projects | +| Build Gateway | `build-gateway.yml` | Tag `v*.*.*` or manual | Build subgraphs, compose gateway, push API image | +| Release | `release.yml` | Tag `v*.*.*` | Build and push all Docker images | +| Claude PR Assistant | `claude_assistant.yml` | Issue/PR comments with @claude | AI-assisted code review and issue handling | + +## Pipeline Architecture + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ Push to master │ +└─────────────────────────────┬───────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────┐ + │ build.yml │ + │ (CI checks) │ + └─────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────┐ +│ Push tag v*.*.* │ +└─────────────────────────────┬───────────────────────────────────────┘ + │ + ┌───────────────┴───────────────┐ + ▼ ▼ +┌─────────────────────────┐ ┌─────────────────────────┐ +│ release.yml │ │ build-gateway.yml │ +│ (build & push all │ │ (build subgraphs & │ +│ backend + frontend) │ │ push API gateway) │ +└─────────────────────────┘ └─────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────┐ +│ Issue/PR comment containing @claude │ +└─────────────────────────────┬───────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────┐ + │ claude_assistant.yml │ + │ (AI code assistance) │ + └─────────────────────────┘ +``` + +## Required Configuration + +### Repository Secrets + +Configure these in **Settings → Actions → Secrets**: + +| Secret | Description | Required By | +|--------|-------------|-------------| +| `REGISTRY_TOKEN` | Gitea access token with `write:package` scope | `release.yml`, `build-gateway.yml` | +| `CLAUDE_CODE_OAUTH_TOKEN` | Claude Code OAuth token | `claude_assistant.yml` | +| `CLAUDE_GITEA_TOKEN` | Gitea token for Claude assistant | `claude_assistant.yml` | + +#### Creating Access Tokens + +1. Go to **Settings → Applications → Access Tokens** +2. Create a new token with the following scopes: + - `write:package` - Push container images + - `write:repository` - For Claude assistant to push commits +3. Copy the token and add it as a repository secret + +### Repository Variables + +Configure these in **Settings → Actions → Variables**: + +| Variable | Description | Example | Required By | +|----------|-------------|---------|-------------| +| `VITE_GRAPHQL_URI` | GraphQL API endpoint URL | `https://api.fictionarchive.example.com/graphql/` | `release.yml` | +| `VITE_OIDC_AUTHORITY` | OIDC provider authority URL | `https://auth.example.com/application/o/fiction-archive/` | `release.yml` | +| `VITE_OIDC_CLIENT_ID` | OIDC client identifier | `your-client-id` | `release.yml` | +| `VITE_OIDC_REDIRECT_URI` | Post-login redirect URL | `https://fictionarchive.example.com/` | `release.yml` | +| `VITE_OIDC_POST_LOGOUT_REDIRECT_URI` | Post-logout redirect URL | `https://fictionarchive.example.com/` | `release.yml` | + +## Workflow Details + +### CI (`build.yml`) + +**Trigger:** Push or pull request to `master` + +**Jobs:** +1. `build-backend` - Builds .NET solution and runs tests +2. `build-frontend` - Builds React application with linting + +**Requirements:** +- .NET 8.0 SDK +- Node.js 20 + +**Steps (Backend):** +1. Checkout repository +2. Setup .NET 8.0 +3. Restore dependencies +4. Build solution (Release, with `SkipFusionBuild=true`) +5. Run tests + +**Steps (Frontend):** +1. Checkout repository +2. Setup Node.js 20 +3. Install dependencies (`npm ci`) +4. Run linter (`npm run lint`) +5. Build application (`npm run build`) + +### Build Gateway (`build-gateway.yml`) + +**Trigger:** +- Manual dispatch (`workflow_dispatch`) +- Push tag matching `v*.*.*` + +**Jobs:** + +#### 1. `build-subgraphs` (Matrix Job) +Builds GraphQL subgraph packages for each service: + +| Service | Project | Subgraph Name | +|---------|---------|---------------| +| novel-service | FictionArchive.Service.NovelService | Novel | +| translation-service | FictionArchive.Service.TranslationService | Translation | +| scheduler-service | FictionArchive.Service.SchedulerService | Scheduler | +| user-service | FictionArchive.Service.UserService | User | + +**Note:** File Service and Authentication Service are not subgraphs (no GraphQL schema). + +**Steps:** +1. Checkout repository +2. Setup .NET 8.0 +3. Install HotChocolate Fusion CLI +4. Restore and build service project +5. Export GraphQL schema (`schema export`) +6. Pack subgraph into `.fsp` file +7. Upload artifact (retained 30 days) + +#### 2. `build-gateway` (Depends on `build-subgraphs`) +Composes the API gateway from subgraph packages. + +**Steps:** +1. Checkout repository +2. Setup .NET 8.0 and Fusion CLI +3. Download all subgraph artifacts +4. Configure Docker-internal URLs (`http://{service}-service:8080/graphql`) +5. Compose gateway schema using Fusion CLI +6. Build gateway project +7. Build and push Docker image + +**Image Tags:** +- `//fictionarchive-api:latest` +- `//fictionarchive-api:` + +### Release (`release.yml`) + +**Trigger:** Push tag matching `v*.*.*` (e.g., `v1.0.0`) + +**Jobs:** + +#### 1. `build-and-push` (Matrix Job) +Builds and pushes all backend service images: + +| Service | Dockerfile | +|---------|------------| +| novel-service | FictionArchive.Service.NovelService/Dockerfile | +| user-service | FictionArchive.Service.UserService/Dockerfile | +| translation-service | FictionArchive.Service.TranslationService/Dockerfile | +| file-service | FictionArchive.Service.FileService/Dockerfile | +| scheduler-service | FictionArchive.Service.SchedulerService/Dockerfile | +| authentication-service | FictionArchive.Service.AuthenticationService/Dockerfile | + +#### 2. `build-frontend` +Builds and pushes the frontend image with environment-specific build arguments. + +**Build Args:** +- `VITE_GRAPHQL_URI` +- `VITE_OIDC_AUTHORITY` +- `VITE_OIDC_CLIENT_ID` +- `VITE_OIDC_REDIRECT_URI` +- `VITE_OIDC_POST_LOGOUT_REDIRECT_URI` + +**Image Tags:** +- `//fictionarchive-:` +- `//fictionarchive-:latest` + +### Claude PR Assistant (`claude_assistant.yml`) + +**Trigger:** Comments or issues containing `@claude`: +- Issue comments +- Pull request review comments +- Pull request reviews +- New issues (opened or assigned) + +**Permissions Required:** +- `contents: write` +- `pull-requests: write` +- `issues: write` +- `id-token: write` + +**Usage:** +Mention `@claude` in any issue or PR comment to invoke the AI assistant for: +- Code review assistance +- Bug analysis +- Implementation suggestions +- Documentation help + +## Container Registry + +Images are pushed to the Gitea Container Registry at: +``` +//fictionarchive-: +``` + +### Image Naming Convention + +| Image | Description | +|-------|-------------| +| `fictionarchive-api` | API Gateway (GraphQL Federation) | +| `fictionarchive-novel-service` | Novel Service | +| `fictionarchive-user-service` | User Service | +| `fictionarchive-translation-service` | Translation Service | +| `fictionarchive-file-service` | File Service | +| `fictionarchive-scheduler-service` | Scheduler Service | +| `fictionarchive-authentication-service` | Authentication Service | +| `fictionarchive-frontend` | Web Frontend | + +### Pulling Images + +```bash +# Login to registry +docker login -u -p + +# Pull an image +docker pull //fictionarchive-api:latest +``` + +## Creating a Release + +1. Ensure all changes are committed and pushed to `master` +2. Create and push a version tag: + ```bash + git tag v1.0.0 + git push origin v1.0.0 + ``` +3. The release workflow will automatically build and push all images +4. Monitor progress in **Actions** tab + +## Troubleshooting + +### Build Failures + +**"REGISTRY_TOKEN secret not found"** +- Ensure the `REGISTRY_TOKEN` secret is configured in repository settings +- Verify the token has `write:package` scope + +**"No subgraph artifacts found"** +- The gateway build requires subgraph artifacts from the `build-subgraphs` job +- If subgraph builds failed, check the matrix job logs for errors + +**"Schema export failed"** +- Ensure the service project has a valid `subgraph-config.json` +- Check that the service starts correctly for schema export + +### Frontend Build Failures + +**"VITE_* variables are empty"** +- Ensure all required variables are configured in repository settings +- Variables use `vars.*` context, not `secrets.*` + +### Docker Push Failures + +**"unauthorized: authentication required"** +- Verify `REGISTRY_TOKEN` has correct permissions +- Check that the token hasn't expired + +### Claude Assistant Failures + +**"Claude assistant not responding"** +- Verify `CLAUDE_CODE_OAUTH_TOKEN` is configured +- Verify `CLAUDE_GITEA_TOKEN` is configured and has write permissions +- Check that the comment contains `@claude` mention + +## Local Testing + +To test workflows locally before pushing: + +```bash +# Install act (GitHub Actions local runner) +# Note: act has partial Gitea Actions compatibility + +# Run CI workflow +act push -W .gitea/workflows/build.yml + +# Run with specific event +act push --eventpath .gitea/test-event.json +``` diff --git a/Documentation/README.md b/Documentation/README.md new file mode 100644 index 0000000..1b80ddb --- /dev/null +++ b/Documentation/README.md @@ -0,0 +1,187 @@ +# FictionArchive + +A distributed microservices-based web application for managing fiction and novel content. Features include importing from external sources, multi-language translation, file storage, and user management. + +## Architecture + +FictionArchive uses a GraphQL Fusion gateway pattern to orchestrate multiple domain services with event-driven communication via RabbitMQ. +More information available in [ARCHITECTURE.md](ARCHITECTURE.md) + +## Prerequisites + +- .NET SDK 8.0+ +- Node.js 20+ +- Python 3 (for gateway build script) +- Docker & Docker Compose +- PostgreSQL 16+ +- RabbitMQ 3+ + +**Required CLI Tools** +```bash +# Hot Chocolate Fusion CLI +dotnet tool install -g HotChocolate.Fusion.CommandLine +``` + +## Getting Started + +### Local Development + +1. **Clone the repository** + ```bash + git clone + cd FictionArchive + ``` + +2. **Start infrastructure** (PostgreSQL, RabbitMQ) + ```bash + docker compose up -d postgres rabbitmq + ``` + +3. **Build and run backend** + ```bash + dotnet restore + dotnet build FictionArchive.sln + + # Start services (in separate terminals or use a process manager) + dotnet run --project FictionArchive.Service.NovelService + dotnet run --project FictionArchive.Service.UserService + dotnet run --project FictionArchive.Service.TranslationService + dotnet run --project FictionArchive.Service.FileService + dotnet run --project FictionArchive.Service.SchedulerService + dotnet run --project FictionArchive.Service.AuthenticationService + + # Start the gateway (builds fusion schema automatically) + dotnet run --project FictionArchive.API + ``` + +4. **Build and run frontend** + ```bash + cd fictionarchive-web + npm install + npm run codegen # Generate GraphQL types + npm run dev # Start dev server at http://localhost:5173 + ``` + +### Docker Deployment + +1. **Create environment file** + ```bash + cp .env.example .env + # Edit .env with your configuration + ``` + +2. **Start all services** + ```bash + docker compose up -d + ``` + +## Configuration + +### Environment Variables + +Create a `.env` file in the project root: + +```bash +# PostgreSQL +POSTGRES_USER=postgres +POSTGRES_PASSWORD=your-secure-password + +# RabbitMQ +RABBITMQ_USER=guest +RABBITMQ_PASSWORD=your-secure-password + +# External Services +NOVELPIA_USERNAME=your-username +NOVELPIA_PASSWORD=your-password +DEEPL_API_KEY=your-api-key + +# S3 Storage +S3_ENDPOINT=https://s3.example.com +S3_BUCKET=fictionarchive +S3_ACCESS_KEY=your-access-key +S3_SECRET_KEY=your-secret-key + +# OIDC Authentication +OIDC_AUTHORITY=https://auth.example.com/application/o/fiction-archive/ +OIDC_CLIENT_ID=your-client-id +``` + +### Frontend Environment + +Create `fictionarchive-web/.env.local`: + +```bash +VITE_GRAPHQL_URI=http://localhost:5234/graphql/ +VITE_OIDC_AUTHORITY=https://auth.example.com/application/o/fiction-archive/ +VITE_OIDC_CLIENT_ID=your-client-id +VITE_OIDC_REDIRECT_URI=http://localhost:5173/ +VITE_OIDC_POST_LOGOUT_REDIRECT_URI=http://localhost:5173/ +``` + +## Building the GraphQL Gateway + +The API gateway uses Hot Chocolate Fusion to compose schemas from all subgraphs. The gateway schema is rebuilt automatically when building the API project. + +**Manual rebuild:** +```bash +cd FictionArchive.API +python build_gateway.py +``` + +**Skip specific services** by adding them to `FictionArchive.API/gateway_skip.txt`: +``` +FictionArchive.Service.NovelService.Tests +``` + +## CI/CD + +The project uses Gitea Actions with the following workflows: + +| Workflow | Trigger | Description | +|----------|---------|-------------| +| `build.yml` | Push/PR to master | CI checks - builds and tests | +| `build-subgraphs.yml` | Service changes on master | Builds subgraph `.fsp` packages | +| `build-gateway.yml` | Gateway changes or subgraph builds | Composes gateway and builds Docker image | +| `release.yml` | Tag `v*.*.*` | Builds and pushes all Docker images | + +### Release Process + +```bash +git tag v1.0.0 +git push origin v1.0.0 +``` + +## Project Structure + +``` +FictionArchive/ +├── FictionArchive.sln +├── FictionArchive.Common/ # Shared enums and extensions +├── FictionArchive.Service.Shared/ # Shared infrastructure (EventBus, DB) +├── FictionArchive.API/ # GraphQL Fusion Gateway +├── FictionArchive.Service.NovelService/ +├── FictionArchive.Service.UserService/ +├── FictionArchive.Service.TranslationService/ +├── FictionArchive.Service.FileService/ +├── FictionArchive.Service.SchedulerService/ +├── FictionArchive.Service.AuthenticationService/ +├── FictionArchive.Service.NovelService.Tests/ +├── fictionarchive-web/ # React frontend +├── docker-compose.yml +└── .gitea/workflows/ # CI/CD workflows +``` + +## Testing + +```bash +# Run all tests +dotnet test FictionArchive.sln + +# Run specific test project +dotnet test FictionArchive.Service.NovelService.Tests +``` + +## Documentation + +- [ARCHITECTURE.md](ARCHITECTURE.md) - Detailed architecture documentation +- [AGENTS.md](AGENTS.md) - Development guidelines and coding standards diff --git a/FictionArchive.API/Dockerfile b/FictionArchive.API/Dockerfile index 18cacd4..e5b1972 100644 --- a/FictionArchive.API/Dockerfile +++ b/FictionArchive.API/Dockerfile @@ -7,15 +7,23 @@ EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src + COPY ["FictionArchive.API/FictionArchive.API.csproj", "FictionArchive.API/"] +COPY ["FictionArchive.Common/FictionArchive.Common.csproj", "FictionArchive.Common/"] +COPY ["FictionArchive.Service.Shared/FictionArchive.Service.Shared.csproj", "FictionArchive.Service.Shared/"] RUN dotnet restore "FictionArchive.API/FictionArchive.API.csproj" -COPY . . + +COPY FictionArchive.API/ FictionArchive.API/ +COPY FictionArchive.Common/ FictionArchive.Common/ +COPY FictionArchive.Service.Shared/ FictionArchive.Service.Shared/ + WORKDIR "/src/FictionArchive.API" -RUN dotnet build "./FictionArchive.API.csproj" -c $BUILD_CONFIGURATION -o /app/build +# Skip fusion build - gateway.fgp should be pre-composed in CI +RUN dotnet build "./FictionArchive.API.csproj" -c $BUILD_CONFIGURATION -o /app/build -p:SkipFusionBuild=true FROM build AS publish ARG BUILD_CONFIGURATION=Release -RUN dotnet publish "./FictionArchive.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false +RUN dotnet publish "./FictionArchive.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false /p:SkipFusionBuild=true FROM base AS final WORKDIR /app diff --git a/FictionArchive.API/FictionArchive.API.csproj b/FictionArchive.API/FictionArchive.API.csproj index 752aa54..73638d7 100644 --- a/FictionArchive.API/FictionArchive.API.csproj +++ b/FictionArchive.API/FictionArchive.API.csproj @@ -22,9 +22,9 @@ - - - + + + diff --git a/FictionArchive.API/build_gateway.py b/FictionArchive.API/build_gateway.py index cb6f68e..a345342 100644 --- a/FictionArchive.API/build_gateway.py +++ b/FictionArchive.API/build_gateway.py @@ -1,12 +1,22 @@ #!/usr/bin/env python3 +""" +Local development script for building the Fusion gateway. + +This script is used for local development only. In CI/CD, subgraphs are built +separately and the gateway is composed from pre-built .fsp artifacts. + +Usage: + python build_gateway.py + +Requirements: + - .NET 8.0 SDK + - HotChocolate Fusion CLI (dotnet tool install -g HotChocolate.Fusion.CommandLine) +""" import subprocess import sys import os from pathlib import Path -# ---------------------------------------- -# Helpers -# ---------------------------------------- def run(cmd, cwd=None): """Run a command and exit on failure.""" @@ -19,7 +29,7 @@ def run(cmd, cwd=None): def load_skip_list(skip_file: Path): if not skip_file.exists(): - print(f"WARNING: skip-projects.txt not found at {skip_file}") + print(f"WARNING: gateway_skip.txt not found at {skip_file}") return set() lines = skip_file.read_text().splitlines() @@ -53,7 +63,7 @@ print("----------------------------------------") service_dirs = [ d for d in services_dir.glob("FictionArchive.Service.*") - if d.is_dir() + if d.is_dir() and (d / "subgraph-config.json").exists() ] selected_services = [] diff --git a/FictionArchive.Common/FictionArchive.Common.csproj b/FictionArchive.Common/FictionArchive.Common.csproj index a4cbc9a..bf3ccde 100644 --- a/FictionArchive.Common/FictionArchive.Common.csproj +++ b/FictionArchive.Common/FictionArchive.Common.csproj @@ -9,14 +9,8 @@ + - - - - ..\..\..\..\..\..\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.15\Microsoft.Extensions.Hosting.Abstractions.dll - - - diff --git a/FictionArchive.Service.FileService/Dockerfile b/FictionArchive.Service.FileService/Dockerfile index f972438..fc45bc8 100644 --- a/FictionArchive.Service.FileService/Dockerfile +++ b/FictionArchive.Service.FileService/Dockerfile @@ -7,17 +7,17 @@ EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src -COPY ["FictionArchive.Service.ImageService/FictionArchive.Service.ImageService.csproj", "FictionArchive.Service.ImageService/"] -RUN dotnet restore "FictionArchive.Service.ImageService/FictionArchive.Service.ImageService.csproj" +COPY ["FictionArchive.Service.FileService/FictionArchive.Service.FileService.csproj", "FictionArchive.Service.FileService/"] +RUN dotnet restore "FictionArchive.Service.FileService/FictionArchive.Service.FileService.csproj" COPY . . -WORKDIR "/src/FictionArchive.Service.ImageService" -RUN dotnet build "./FictionArchive.Service.ImageService.csproj" -c $BUILD_CONFIGURATION -o /app/build +WORKDIR "/src/FictionArchive.Service.FileService" +RUN dotnet build "./FictionArchive.Service.FileService.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release -RUN dotnet publish "./FictionArchive.Service.ImageService.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false +RUN dotnet publish "./FictionArchive.Service.FileService.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "FictionArchive.Service.ImageService.dll"] +ENTRYPOINT ["dotnet", "FictionArchive.Service.FileService.dll"] diff --git a/FictionArchive.Service.FileService/appsettings.json b/FictionArchive.Service.FileService/appsettings.json index c18d35f..0f6f7a4 100644 --- a/FictionArchive.Service.FileService/appsettings.json +++ b/FictionArchive.Service.FileService/appsettings.json @@ -9,7 +9,7 @@ "BaseUrl": "https://localhost:7247/api" }, "RabbitMQ": { - "ConnectionString": "amqp://localhost", + "ConnectionString": "amqp://localhost2", "ClientIdentifier": "FileService" }, "S3": { diff --git a/FictionArchive.Service.NovelService/GraphQL/Mutation.cs b/FictionArchive.Service.NovelService/GraphQL/Mutation.cs index 7b014f5..15f92a7 100644 --- a/FictionArchive.Service.NovelService/GraphQL/Mutation.cs +++ b/FictionArchive.Service.NovelService/GraphQL/Mutation.cs @@ -12,26 +12,15 @@ namespace FictionArchive.Service.NovelService.GraphQL; public class Mutation { - public async Task ImportNovel(string novelUrl, IEventBus eventBus) + public async Task ImportNovel(string novelUrl, NovelUpdateService service) { - var importNovelRequestEvent = new NovelUpdateRequestedEvent() - { - NovelUrl = novelUrl - }; - await eventBus.Publish(importNovelRequestEvent); - return importNovelRequestEvent; + return await service.QueueNovelImport(novelUrl); } public async Task FetchChapterContents(uint novelId, uint chapterNumber, - IEventBus eventBus) + NovelUpdateService service) { - var chapterPullEvent = new ChapterPullRequestedEvent() - { - NovelId = novelId, - ChapterNumber = chapterNumber - }; - await eventBus.Publish(chapterPullEvent); - return chapterPullEvent; + return await service.QueueChapterPull(novelId, chapterNumber); } } \ No newline at end of file diff --git a/FictionArchive.Service.NovelService/Program.cs b/FictionArchive.Service.NovelService/Program.cs index 68fe593..ff9fd26 100644 --- a/FictionArchive.Service.NovelService/Program.cs +++ b/FictionArchive.Service.NovelService/Program.cs @@ -6,6 +6,7 @@ using FictionArchive.Service.NovelService.Services; using FictionArchive.Service.NovelService.Services.EventHandlers; using FictionArchive.Service.NovelService.Services.SourceAdapters; using FictionArchive.Service.NovelService.Services.SourceAdapters.Novelpia; +using FictionArchive.Service.Shared; using FictionArchive.Service.Shared.Extensions; using FictionArchive.Service.Shared.Services.EventBus.Implementations; using FictionArchive.Service.Shared.Services.GraphQL; @@ -17,6 +18,8 @@ public class Program { public static void Main(string[] args) { + var isSchemaExport = SchemaExportDetector.IsSchemaExportMode(args); + var builder = WebApplication.CreateBuilder(args); builder.AddLocalAppsettings(); @@ -24,15 +27,18 @@ public class Program #region Event Bus - builder.Services.AddRabbitMQ(opt => + if (!isSchemaExport) { - builder.Configuration.GetSection("RabbitMQ").Bind(opt); - }) - .Subscribe() - .Subscribe() - .Subscribe() - .Subscribe(); - + builder.Services.AddRabbitMQ(opt => + { + builder.Configuration.GetSection("RabbitMQ").Bind(opt); + }) + .Subscribe() + .Subscribe() + .Subscribe() + .Subscribe(); + } + #endregion #region GraphQL @@ -43,7 +49,9 @@ public class Program #region Database - builder.Services.RegisterDbContext(builder.Configuration.GetConnectionString("DefaultConnection")); + builder.Services.RegisterDbContext( + builder.Configuration.GetConnectionString("DefaultConnection"), + skipInfrastructure: isSchemaExport); #endregion @@ -69,9 +77,10 @@ public class Program var app = builder.Build(); - // Update database - using (var scope = app.Services.CreateScope()) + // Update database (skip in schema export mode) + if (!isSchemaExport) { + using var scope = app.Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); dbContext.UpdateDatabase(); } diff --git a/FictionArchive.Service.NovelService/Services/NovelUpdateService.cs b/FictionArchive.Service.NovelService/Services/NovelUpdateService.cs index de3438b..862dcbe 100644 --- a/FictionArchive.Service.NovelService/Services/NovelUpdateService.cs +++ b/FictionArchive.Service.NovelService/Services/NovelUpdateService.cs @@ -2,6 +2,7 @@ using FictionArchive.Service.FileService.IntegrationEvents; using FictionArchive.Service.NovelService.Models.Configuration; using FictionArchive.Service.NovelService.Models.Enums; using FictionArchive.Service.NovelService.Models.Images; +using FictionArchive.Service.NovelService.Models.IntegrationEvents; using FictionArchive.Service.NovelService.Models.Localization; using FictionArchive.Service.NovelService.Models.Novels; using FictionArchive.Service.NovelService.Models.SourceAdapters; @@ -201,4 +202,25 @@ public class NovelUpdateService await _dbContext.SaveChangesAsync(); } + + public async Task QueueNovelImport(string novelUrl) + { + var importNovelRequestEvent = new NovelUpdateRequestedEvent() + { + NovelUrl = novelUrl + }; + await _eventBus.Publish(importNovelRequestEvent); + return importNovelRequestEvent; + } + + public async Task QueueChapterPull(uint novelId, uint chapterNumber) + { + var chapterPullEvent = new ChapterPullRequestedEvent() + { + NovelId = novelId, + ChapterNumber = chapterNumber + }; + await _eventBus.Publish(chapterPullEvent); + return chapterPullEvent; + } } diff --git a/FictionArchive.Service.SchedulerService/Program.cs b/FictionArchive.Service.SchedulerService/Program.cs index 9d40de1..01e47d9 100644 --- a/FictionArchive.Service.SchedulerService/Program.cs +++ b/FictionArchive.Service.SchedulerService/Program.cs @@ -1,5 +1,6 @@ using FictionArchive.Service.SchedulerService.GraphQL; using FictionArchive.Service.SchedulerService.Services; +using FictionArchive.Service.Shared; using FictionArchive.Service.Shared.Extensions; using FictionArchive.Service.Shared.Services.EventBus.Implementations; using Quartz; @@ -11,6 +12,8 @@ public class Program { public static void Main(string[] args) { + var isSchemaExport = SchemaExportDetector.IsSchemaExportMode(args); + var builder = WebApplication.CreateBuilder(args); // Services @@ -20,45 +23,63 @@ public class Program #region Database - builder.Services.RegisterDbContext(builder.Configuration.GetConnectionString("DefaultConnection")); + builder.Services.RegisterDbContext( + builder.Configuration.GetConnectionString("DefaultConnection"), + skipInfrastructure: isSchemaExport); #endregion #region Event Bus - builder.Services.AddRabbitMQ(opt => + if (!isSchemaExport) { - builder.Configuration.GetSection("RabbitMQ").Bind(opt); - }); - + builder.Services.AddRabbitMQ(opt => + { + builder.Configuration.GetSection("RabbitMQ").Bind(opt); + }); + } + #endregion #region Quartz - builder.Services.AddQuartz(opt => + if (isSchemaExport) { - opt.UsePersistentStore(pso => + // Schema export mode: use in-memory store (no DB connection needed) + builder.Services.AddQuartz(opt => { - pso.UsePostgres(pgsql => - { - pgsql.ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection"); - pgsql.UseDriverDelegate(); - pgsql.TablePrefix = "quartz.qrtz_"; // Needed for Postgres due to the differing schema used - }); - pso.UseNewtonsoftJsonSerializer(); + opt.UseInMemoryStore(); }); - }); - builder.Services.AddQuartzHostedService(opt => + } + else { - opt.WaitForJobsToComplete = true; - }); - + builder.Services.AddQuartz(opt => + { + opt.UsePersistentStore(pso => + { + pso.UsePostgres(pgsql => + { + pgsql.ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection"); + pgsql.UseDriverDelegate(); + pgsql.TablePrefix = "quartz.qrtz_"; // Needed for Postgres due to the differing schema used + }); + pso.UseNewtonsoftJsonSerializer(); + }); + }); + builder.Services.AddQuartzHostedService(opt => + { + opt.WaitForJobsToComplete = true; + }); + } + #endregion var app = builder.Build(); - using (var scope = app.Services.CreateScope()) + // Update database (skip in schema export mode) + if (!isSchemaExport) { + using var scope = app.Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); dbContext.UpdateDatabase(); } diff --git a/FictionArchive.Service.Shared/Extensions/DatabaseExtensions.cs b/FictionArchive.Service.Shared/Extensions/DatabaseExtensions.cs index c373f51..03b2a01 100644 --- a/FictionArchive.Service.Shared/Extensions/DatabaseExtensions.cs +++ b/FictionArchive.Service.Shared/Extensions/DatabaseExtensions.cs @@ -6,16 +6,29 @@ namespace FictionArchive.Service.Shared.Extensions; public static class DatabaseExtensions { - public static IServiceCollection RegisterDbContext(this IServiceCollection services, - string connectionString) where TContext : FictionArchiveDbContext + public static IServiceCollection RegisterDbContext( + this IServiceCollection services, + string connectionString, + bool skipInfrastructure = false) where TContext : FictionArchiveDbContext { - services.AddDbContext(options => + if (skipInfrastructure) { - options.UseNpgsql(connectionString, o => + // For schema export: use in-memory provider to allow EF Core entity discovery + services.AddDbContext(options => { - o.UseNodaTime(); + options.UseInMemoryDatabase($"SchemaExport_{typeof(TContext).Name}"); }); - }); + } + else + { + services.AddDbContext(options => + { + options.UseNpgsql(connectionString, o => + { + o.UseNodaTime(); + }); + }); + } return services; } } \ No newline at end of file diff --git a/FictionArchive.Service.Shared/FictionArchive.Service.Shared.csproj b/FictionArchive.Service.Shared/FictionArchive.Service.Shared.csproj index da7c156..ee7c426 100644 --- a/FictionArchive.Service.Shared/FictionArchive.Service.Shared.csproj +++ b/FictionArchive.Service.Shared/FictionArchive.Service.Shared.csproj @@ -18,6 +18,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all diff --git a/FictionArchive.Service.Shared/SchemaExportDetector.cs b/FictionArchive.Service.Shared/SchemaExportDetector.cs new file mode 100644 index 0000000..024860d --- /dev/null +++ b/FictionArchive.Service.Shared/SchemaExportDetector.cs @@ -0,0 +1,22 @@ +namespace FictionArchive.Service.Shared; + +/// +/// Detects if the application is running in schema export mode (for HotChocolate CLI commands). +/// In this mode, infrastructure like RabbitMQ and databases should not be initialized. +/// +public static class SchemaExportDetector +{ + /// + /// Checks if the current run is a schema export command. + /// + /// Command line arguments passed to Main() + /// True if running schema export, false otherwise + public static bool IsSchemaExportMode(string[] args) + { + // HotChocolate CLI pattern: "schema export" after "--" delimiter + // Handles: dotnet run -- schema export --output schema.graphql + var normalizedArgs = args.SkipWhile(a => a == "--").ToArray(); + return normalizedArgs.Length > 0 && + normalizedArgs[0].Equals("schema", StringComparison.OrdinalIgnoreCase); + } +} diff --git a/FictionArchive.Service.TranslationService/Program.cs b/FictionArchive.Service.TranslationService/Program.cs index 3fb305c..c110f78 100644 --- a/FictionArchive.Service.TranslationService/Program.cs +++ b/FictionArchive.Service.TranslationService/Program.cs @@ -1,5 +1,6 @@ using DeepL; using FictionArchive.Common.Extensions; +using FictionArchive.Service.Shared; using FictionArchive.Service.Shared.Extensions; using FictionArchive.Service.Shared.Services.EventBus.Implementations; using FictionArchive.Service.Shared.Services.GraphQL; @@ -18,6 +19,8 @@ public class Program { public static void Main(string[] args) { + var isSchemaExport = SchemaExportDetector.IsSchemaExportMode(args); + var builder = WebApplication.CreateBuilder(args); builder.AddLocalAppsettings(); @@ -25,18 +28,23 @@ public class Program #region Event Bus - builder.Services.AddRabbitMQ(opt => + if (!isSchemaExport) { - builder.Configuration.GetSection("RabbitMQ").Bind(opt); - }) - .Subscribe(); - + builder.Services.AddRabbitMQ(opt => + { + builder.Configuration.GetSection("RabbitMQ").Bind(opt); + }) + .Subscribe(); + } + #endregion #region Database - builder.Services.RegisterDbContext(builder.Configuration.GetConnectionString("DefaultConnection")); + builder.Services.RegisterDbContext( + builder.Configuration.GetConnectionString("DefaultConnection"), + skipInfrastructure: isSchemaExport); #endregion @@ -60,9 +68,10 @@ public class Program var app = builder.Build(); - // Update database - using (var scope = app.Services.CreateScope()) + // Update database (skip in schema export mode) + if (!isSchemaExport) { + using var scope = app.Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); dbContext.UpdateDatabase(); } diff --git a/FictionArchive.Service.UserService/Program.cs b/FictionArchive.Service.UserService/Program.cs index 13c397d..efc54e9 100644 --- a/FictionArchive.Service.UserService/Program.cs +++ b/FictionArchive.Service.UserService/Program.cs @@ -1,3 +1,4 @@ +using FictionArchive.Service.Shared; using FictionArchive.Service.Shared.Extensions; using FictionArchive.Service.Shared.Services.EventBus.Implementations; using FictionArchive.Service.UserService.GraphQL; @@ -11,16 +12,21 @@ public class Program { public static void Main(string[] args) { + var isSchemaExport = SchemaExportDetector.IsSchemaExportMode(args); + var builder = WebApplication.CreateBuilder(args); #region Event Bus - builder.Services.AddRabbitMQ(opt => + if (!isSchemaExport) { - builder.Configuration.GetSection("RabbitMQ").Bind(opt); - }) - .Subscribe(); - + builder.Services.AddRabbitMQ(opt => + { + builder.Configuration.GetSection("RabbitMQ").Bind(opt); + }) + .Subscribe(); + } + #endregion #region GraphQL @@ -29,16 +35,19 @@ public class Program #endregion - builder.Services.RegisterDbContext(builder.Configuration.GetConnectionString("DefaultConnection")); + builder.Services.RegisterDbContext( + builder.Configuration.GetConnectionString("DefaultConnection"), + skipInfrastructure: isSchemaExport); builder.Services.AddTransient(); builder.Services.AddHealthChecks(); var app = builder.Build(); - // Update database - using (var scope = app.Services.CreateScope()) + // Update database (skip in schema export mode) + if (!isSchemaExport) { + using var scope = app.Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); dbContext.UpdateDatabase(); } diff --git a/README.md b/README.md new file mode 100644 index 0000000..bec8f84 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# FictionArchive + +A distributed microservices-based web application for managing fiction and novel content. + +## Documentation + +- [README](Documentation/README.md) - Getting started and project overview +- [ARCHITECTURE](Documentation/ARCHITECTURE.md) - System architecture and design +- [CICD](Documentation/CICD.md) - CI/CD pipeline configuration +- [AGENTS](Documentation/AGENTS.md) - Development guidelines and coding standards diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2978d78 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,195 @@ +services: + # =========================================== + # Infrastructure + # =========================================== + postgres: + image: postgres:16-alpine + environment: + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + restart: unless-stopped + + rabbitmq: + image: rabbitmq:3-management-alpine + environment: + RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-guest} + RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-guest} + volumes: + - rabbitmq_data:/var/lib/rabbitmq + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "check_running"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + + # =========================================== + # Backend Services + # =========================================== + novel-service: + image: git.orfl.xyz/conco/fictionarchive-novel-service:latest + environment: + ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_NovelService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} + ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq + Novelpia__Username: ${NOVELPIA_USERNAME} + Novelpia__Password: ${NOVELPIA_PASSWORD} + NovelUpdateService__PendingImageUrl: https://files.fictionarchive.orfl.xyz/api/pendingupload.png + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + depends_on: + postgres: + condition: service_healthy + rabbitmq: + condition: service_healthy + restart: unless-stopped + + translation-service: + image: git.orfl.xyz/conco/fictionarchive-translation-service:latest + environment: + ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_TranslationService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} + ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq + DeepL__ApiKey: ${DEEPL_API_KEY} + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + depends_on: + postgres: + condition: service_healthy + rabbitmq: + condition: service_healthy + restart: unless-stopped + + scheduler-service: + image: git.orfl.xyz/conco/fictionarchive-scheduler-service:latest + environment: + ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_SchedulerService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} + ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + depends_on: + postgres: + condition: service_healthy + rabbitmq: + condition: service_healthy + restart: unless-stopped + + user-service: + image: git.orfl.xyz/conco/fictionarchive-user-service:latest + environment: + ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_UserService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} + ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + depends_on: + postgres: + condition: service_healthy + rabbitmq: + condition: service_healthy + restart: unless-stopped + + authentication-service: + image: git.orfl.xyz/conco/fictionarchive-authentication-service:latest + environment: + ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + depends_on: + rabbitmq: + condition: service_healthy + restart: unless-stopped + + file-service: + image: git.orfl.xyz/conco/fictionarchive-file-service:latest + environment: + ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq + S3__Endpoint: ${S3_ENDPOINT:-https://s3.orfl.xyz} + S3__Bucket: ${S3_BUCKET:-fictionarchive} + S3__AccessKey: ${S3_ACCESS_KEY} + S3__SecretKey: ${S3_SECRET_KEY} + Proxy__BaseUrl: https://files.orfl.xyz/api + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + labels: + - "traefik.enable=true" + - "traefik.http.routers.file-service.rule=Host(`files.orfl.xyz`)" + - "traefik.http.routers.file-service.entrypoints=websecure" + - "traefik.http.routers.file-service.tls.certresolver=letsencrypt" + - "traefik.http.services.file-service.loadbalancer.server.port=8080" + depends_on: + rabbitmq: + condition: service_healthy + restart: unless-stopped + + # =========================================== + # API Gateway + # =========================================== + api-gateway: + image: git.orfl.xyz/conco/fictionarchive-api:latest + environment: + ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 30s + timeout: 10s + retries: 3 + labels: + - "traefik.enable=true" + - "traefik.http.routers.api-gateway.rule=Host(`api.fictionarchive.orfl.xyz`)" + - "traefik.http.routers.api-gateway.entrypoints=websecure" + - "traefik.http.routers.api-gateway.tls.certresolver=letsencrypt" + - "traefik.http.services.api-gateway.loadbalancer.server.port=8080" + depends_on: + - novel-service + - translation-service + - scheduler-service + - user-service + - authentication-service + - file-service + restart: unless-stopped + + # =========================================== + # Frontend + # =========================================== + frontend: + image: git.orfl.xyz/conco/fictionarchive-frontend:latest + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost/"] + interval: 30s + timeout: 10s + retries: 3 + labels: + - "traefik.enable=true" + - "traefik.http.routers.frontend.rule=Host(`fictionarchive.orfl.xyz`)" + - "traefik.http.routers.frontend.entrypoints=websecure" + - "traefik.http.routers.frontend.tls.certresolver=letsencrypt" + - "traefik.http.services.frontend.loadbalancer.server.port=80" + restart: unless-stopped + +volumes: + postgres_data: + rabbitmq_data: + letsencrypt: diff --git a/fictionarchive-web/.dockerignore b/fictionarchive-web/.dockerignore new file mode 100644 index 0000000..8d3531b --- /dev/null +++ b/fictionarchive-web/.dockerignore @@ -0,0 +1,40 @@ +# Dependencies +node_modules + +# Build output +dist + +# Environment files +.env +.env.local +.env.*.local + +# IDE and editor +.vscode +.idea +*.swp +*.swo + +# Git +.git +.gitignore + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Test coverage +coverage + +# Docker +Dockerfile +.dockerignore +docker-compose* + +# Documentation +README.md +*.md + +# TypeScript build info +*.tsbuildinfo diff --git a/fictionarchive-web/.gitignore b/fictionarchive-web/.gitignore index 5e65573..a547bf3 100644 --- a/fictionarchive-web/.gitignore +++ b/fictionarchive-web/.gitignore @@ -12,9 +12,6 @@ dist dist-ssr *.local -# Generated GraphQL artifacts -src/__generated__/ - # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/fictionarchive-web/Dockerfile b/fictionarchive-web/Dockerfile new file mode 100644 index 0000000..9b9a813 --- /dev/null +++ b/fictionarchive-web/Dockerfile @@ -0,0 +1,32 @@ +FROM node:20-alpine AS build + +WORKDIR /app + +# Build arguments for Vite environment variables +ARG VITE_GRAPHQL_URI +ARG VITE_OIDC_AUTHORITY +ARG VITE_OIDC_CLIENT_ID +ARG VITE_OIDC_REDIRECT_URI +ARG VITE_OIDC_POST_LOGOUT_REDIRECT_URI + +# Set environment variables for build +ENV VITE_GRAPHQL_URI=$VITE_GRAPHQL_URI +ENV VITE_OIDC_AUTHORITY=$VITE_OIDC_AUTHORITY +ENV VITE_OIDC_CLIENT_ID=$VITE_OIDC_CLIENT_ID +ENV VITE_OIDC_REDIRECT_URI=$VITE_OIDC_REDIRECT_URI +ENV VITE_OIDC_POST_LOGOUT_REDIRECT_URI=$VITE_OIDC_POST_LOGOUT_REDIRECT_URI + +COPY package*.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +FROM nginx:alpine + +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/fictionarchive-web/README.md b/fictionarchive-web/README.md index ff73def..03b9e20 100644 --- a/fictionarchive-web/README.md +++ b/fictionarchive-web/README.md @@ -25,8 +25,8 @@ VITE_CODEGEN_TOKEN=your_api_token ## Scripts - `npm run dev`: start Vite dev server. -- `npm run build`: type-check + build (runs codegen first via `prebuild`). -- `npm run codegen`: generate typed hooks from `src/**/*.graphql` into `src/__generated__/graphql.ts`. +- `npm run build`: type-check + production build. +- `npm run codegen`: generate typed hooks from `src/**/*.graphql` into `src/__generated__/graphql.ts`. **Run this manually after changing GraphQL operations or when the gateway schema changes.** ## Project notes @@ -39,4 +39,4 @@ VITE_CODEGEN_TOKEN=your_api_token - Default schema URL: `CODEGEN_SCHEMA_URL` (falls back to `VITE_GRAPHQL_URI`, then `https://localhost:5001/graphql`). - Add `VITE_CODEGEN_TOKEN` (or `CODEGEN_TOKEN`) if your gateway requires a bearer token during introspection. -- Generated outputs land in `src/__generated__/graphql.ts` (git-ignored). Run `npm run codegen` after schema/operation changes or rely on `npm run build` (runs `prebuild`). +- Generated outputs land in `src/__generated__/graphql.ts` (committed to git). Run `npm run codegen` after schema/operation changes. diff --git a/fictionarchive-web/codegen.ts b/fictionarchive-web/codegen.ts index c4d3d4b..89136b3 100644 --- a/fictionarchive-web/codegen.ts +++ b/fictionarchive-web/codegen.ts @@ -22,15 +22,17 @@ const config: CodegenConfig = { plugins: [ 'typescript', 'typescript-operations', - 'typescript-react-apollo', + 'typed-document-node', ], config: { - withHooks: true, - avoidOptionals: true, - dedupeFragments: true, + avoidOptionals: { + field: true, + inputValue: false, + }, + enumsAsConst: true, maybeValue: 'T | null', skipTypename: true, - apolloReactHooksImportFrom: '@apollo/client/react', + useTypeImports: true, }, }, }, diff --git a/fictionarchive-web/eslint.config.js b/fictionarchive-web/eslint.config.js index 5e6b472..7dd669d 100644 --- a/fictionarchive-web/eslint.config.js +++ b/fictionarchive-web/eslint.config.js @@ -6,7 +6,7 @@ import tseslint from 'typescript-eslint' import { defineConfig, globalIgnores } from 'eslint/config' export default defineConfig([ - globalIgnores(['dist']), + globalIgnores(['dist', 'src/__generated__']), { files: ['**/*.{ts,tsx}'], extends: [ diff --git a/fictionarchive-web/nginx.conf b/fictionarchive-web/nginx.conf new file mode 100644 index 0000000..da7ddcb --- /dev/null +++ b/fictionarchive-web/nginx.conf @@ -0,0 +1,21 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # Handle SPA routing - serve index.html for all routes + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} diff --git a/fictionarchive-web/package-lock.json b/fictionarchive-web/package-lock.json index 2248c06..f01efe1 100644 --- a/fictionarchive-web/package-lock.json +++ b/fictionarchive-web/package-lock.json @@ -22,9 +22,9 @@ "devDependencies": { "@eslint/js": "^9.39.1", "@graphql-codegen/cli": "^5.0.3", + "@graphql-codegen/typed-document-node": "^6.1.1", "@graphql-codegen/typescript": "^4.0.9", "@graphql-codegen/typescript-operations": "^4.0.9", - "@graphql-codegen/typescript-react-apollo": "^4.0.9", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", @@ -60,6 +60,12 @@ "version": "4.0.9", "resolved": "https://registry.npmjs.org/@apollo/client/-/client-4.0.9.tgz", "integrity": "sha512-Lh2drMzFE9x5jVS8RKmlGL5SORkvpyUJIT+wTErxDUR2HpWePiBfhhcHHRSlZFiCR866ewCv4euTc4IDF0GWxw==", + "license": "MIT", + "workspaces": [ + "dist", + "codegen", + "scripts/codemods/ac3-to-ac4" + ], "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "@wry/caches": "^1.0.0", @@ -122,6 +128,7 @@ "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", @@ -136,6 +143,7 @@ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -145,6 +153,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", @@ -176,6 +185,7 @@ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", @@ -187,24 +197,12 @@ "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==", - "dev": true, - "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", "@babel/helper-validator-option": "^7.27.1", @@ -216,47 +214,12 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@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.5", - "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, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, "engines": { "node": ">=6.9.0" } @@ -266,6 +229,7 @@ "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" @@ -279,6 +243,7 @@ "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", @@ -291,56 +256,12 @@ "@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==", - "dev": true, - "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, - "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==", - "dev": true, "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, "engines": { "node": ">=6.9.0" } @@ -350,6 +271,7 @@ "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" } @@ -359,6 +281,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -368,6 +291,7 @@ "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" } @@ -377,6 +301,7 @@ "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" @@ -390,6 +315,7 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.28.5" }, @@ -400,74 +326,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", - "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", - "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-syntax-import-assertions": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", @@ -484,329 +342,12 @@ "@babel/core": "^7.0.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==", - "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-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.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-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "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-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", - "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-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", - "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-flow": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "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-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "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-modules-commonjs": { - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "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-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "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-display-name": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", - "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", - "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": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", - "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/types": "^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" }, @@ -822,54 +363,6 @@ "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, - "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-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "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-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -896,6 +389,7 @@ "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", @@ -910,6 +404,7 @@ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -928,6 +423,7 @@ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" @@ -988,6 +484,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -1004,6 +501,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1020,6 +518,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1036,6 +535,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1052,6 +552,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1068,6 +569,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1084,6 +586,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -1100,6 +603,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -1116,6 +620,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1132,6 +637,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1148,6 +654,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1164,6 +671,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1180,6 +688,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1196,6 +705,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1212,6 +722,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1228,6 +739,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1244,6 +756,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1260,6 +773,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -1276,6 +790,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -1292,6 +807,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -1308,6 +824,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -1324,6 +841,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openharmony" @@ -1340,6 +858,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -1356,6 +875,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1372,6 +892,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1388,6 +909,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1401,6 +923,7 @@ "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" }, @@ -1419,6 +942,7 @@ "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" }, @@ -1431,6 +955,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -1440,6 +965,7 @@ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", @@ -1454,6 +980,7 @@ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0" }, @@ -1466,6 +993,7 @@ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, @@ -1478,6 +1006,7 @@ "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", @@ -1501,6 +1030,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -1513,6 +1043,7 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1525,6 +1056,7 @@ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1534,6 +1066,7 @@ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" @@ -1666,6 +1199,26 @@ } } }, + "node_modules/@graphql-codegen/client-preset/node_modules/@graphql-codegen/typed-document-node": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.1.2.tgz", + "integrity": "sha512-jaxfViDqFRbNQmfKwUY8hDyjnLTw2Z7DhGutxoOiiAI0gE/LfPe0LYaVFKVmVOOD7M3bWxoWfu4slrkbWbUbEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.1.0", + "@graphql-codegen/visitor-plugin-common": "5.8.0", + "auto-bind": "~4.0.0", + "change-case-all": "1.0.15", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, "node_modules/@graphql-codegen/client-preset/node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -1774,14 +1327,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typed-document-node": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.1.2.tgz", - "integrity": "sha512-jaxfViDqFRbNQmfKwUY8hDyjnLTw2Z7DhGutxoOiiAI0gE/LfPe0LYaVFKVmVOOD7M3bWxoWfu4slrkbWbUbEw==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.1.3.tgz", + "integrity": "sha512-U1+16S3EWnR4T5b9219pu/47InfDB3UZ2E/CihJXgkeSklNteNBtw3D8m9R+ZanIq/GIsEin2hYpR++PO6neLQ==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/visitor-plugin-common": "5.8.0", + "@graphql-codegen/plugin-helpers": "^6.1.0", + "@graphql-codegen/visitor-plugin-common": "6.2.0", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", "tslib": "~2.6.0" @@ -1793,6 +1346,62 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/typed-document-node/node_modules/@graphql-codegen/plugin-helpers": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.1.0.tgz", + "integrity": "sha512-JJypehWTcty9kxKiqH7TQOetkGdOYjY78RHlI+23qB59cV2wxjFFVf8l7kmuXS4cpGVUNfIjFhVr7A1W7JMtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "change-case-all": "1.0.15", + "common-tags": "1.8.2", + "import-from": "4.0.0", + "lodash": "~4.17.0", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/typed-document-node/node_modules/@graphql-codegen/visitor-plugin-common": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.2.0.tgz", + "integrity": "sha512-8mx5uDDEwhP3G1jdeBdvVm4QhbEdkwXQa1hAXBWGofL87ePs5PUhz4IuQpwiS/CfFa4cqxcAWbe0k74x8iWfKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^6.1.0", + "@graphql-tools/optimize": "^2.0.0", + "@graphql-tools/relay-operation-optimizer": "^7.0.0", + "@graphql-tools/utils": "^10.0.0", + "auto-bind": "~4.0.0", + "change-case-all": "1.0.15", + "dependency-graph": "^1.0.0", + "graphql-tag": "^2.11.0", + "parse-filepath": "^1.0.2", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/typed-document-node/node_modules/dependency-graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz", + "integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@graphql-codegen/typed-document-node/node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -1853,266 +1462,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/@graphql-codegen/typescript-react-apollo": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-react-apollo/-/typescript-react-apollo-4.3.3.tgz", - "integrity": "sha512-ecuzzqoZEHCtlxaEXL1LQTrfzVYwNNtbVUBHc/KQDfkJIQZon+dG5ZXOoJ4BpbRA2L99yTx+TZc2VkpOVfSypw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-codegen/plugin-helpers": "^3.0.0", - "@graphql-codegen/visitor-plugin-common": "2.13.8", - "auto-bind": "~4.0.0", - "change-case-all": "1.0.15", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">= 16.0.0" - }, - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@ardatan/relay-compiler": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz", - "integrity": "sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", - "@babel/parser": "^7.14.0", - "@babel/runtime": "^7.0.0", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.0.0", - "babel-preset-fbjs": "^3.4.0", - "chalk": "^4.0.0", - "fb-watchman": "^2.0.0", - "fbjs": "^3.0.0", - "glob": "^7.1.1", - "immutable": "~3.7.6", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "relay-runtime": "12.0.0", - "signedsource": "^1.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "relay-compiler": "bin/relay-compiler" - }, - "peerDependencies": { - "graphql": "*" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@graphql-codegen/plugin-helpers": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz", - "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-tools/utils": "^9.0.0", - "change-case-all": "1.0.15", - "common-tags": "1.8.2", - "import-from": "4.0.0", - "lodash": "~4.17.0", - "tslib": "~2.4.0" - }, - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@graphql-codegen/plugin-helpers/node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "2.13.8", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.13.8.tgz", - "integrity": "sha512-IQWu99YV4wt8hGxIbBQPtqRuaWZhkQRG2IZKbMoSvh0vGeWb3dB0n0hSgKaOOxDY+tljtOf9MTcUYvJslQucMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-codegen/plugin-helpers": "^3.1.2", - "@graphql-tools/optimize": "^1.3.0", - "@graphql-tools/relay-operation-optimizer": "^6.5.0", - "@graphql-tools/utils": "^9.0.0", - "auto-bind": "~4.0.0", - "change-case-all": "1.0.15", - "dependency-graph": "^0.11.0", - "graphql-tag": "^2.11.0", - "parse-filepath": "^1.0.2", - "tslib": "~2.4.0" - }, - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@graphql-codegen/visitor-plugin-common/node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true, - "license": "0BSD" - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@graphql-tools/optimize": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/optimize/-/optimize-1.4.0.tgz", - "integrity": "sha512-dJs/2XvZp+wgHH8T5J2TqptT9/6uVzIYvA6uFACha+ufvdMBedkfR4b4GbT8jAKLRARiqRTxy3dctnwkTM2tdw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.4.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@graphql-tools/relay-operation-optimizer": { - "version": "6.5.18", - "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.5.18.tgz", - "integrity": "sha512-mc5VPyTeV+LwiM+DNvoDQfPqwQYhPV/cl5jOBjTgSniyaq8/86aODfMkrE2OduhQ5E00hqrkuL2Fdrgk0w1QJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ardatan/relay-compiler": "12.0.0", - "@graphql-tools/utils": "^9.2.1", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@graphql-codegen/typescript-react-apollo/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@graphql-codegen/typescript/node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -2486,16 +1835,6 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/import/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@graphql-tools/json-file-loader": { "version": "8.0.24", "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.24.tgz", @@ -2705,6 +2044,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } @@ -2714,6 +2054,7 @@ "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" } @@ -2723,6 +2064,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" @@ -2736,6 +2078,7 @@ "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" }, @@ -2749,6 +2092,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -2784,6 +2128,7 @@ "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" @@ -2794,6 +2139,7 @@ "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" @@ -2804,6 +2150,7 @@ "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" } @@ -2812,13 +2159,15 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true + "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" @@ -2829,6 +2178,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2842,6 +2192,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -2851,6 +2202,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2912,7 +2264,8 @@ "version": "1.0.0-beta.47", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.53.3", @@ -2922,6 +2275,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -2935,6 +2289,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -2948,6 +2303,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2961,6 +2317,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2974,6 +2331,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -2987,6 +2345,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3000,6 +2359,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3013,6 +2373,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3026,6 +2387,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3039,6 +2401,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3052,6 +2415,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3065,6 +2429,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3078,6 +2443,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3091,6 +2457,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3104,6 +2471,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3117,6 +2485,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3130,6 +2499,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3143,6 +2513,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openharmony" @@ -3156,6 +2527,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3169,6 +2541,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3182,6 +2555,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3195,6 +2569,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3224,6 +2599,7 @@ "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", @@ -3237,6 +2613,7 @@ "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" } @@ -3246,6 +2623,7 @@ "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" @@ -3256,6 +2634,7 @@ "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" } @@ -3264,7 +2643,8 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/js-yaml": { "version": "4.0.9", @@ -3277,23 +2657,26 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "undici-types": "~7.16.0" } }, "node_modules/@types/react": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.6.tgz", - "integrity": "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "devOptional": true, + "license": "MIT", "peer": true, "dependencies": { "csstype": "^3.2.2" @@ -3304,6 +2687,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, + "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" } @@ -3319,16 +2703,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.47.0.tgz", - "integrity": "sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", + "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/type-utils": "8.47.0", - "@typescript-eslint/utils": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/type-utils": "8.48.0", + "@typescript-eslint/utils": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -3342,7 +2727,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.47.0", + "@typescript-eslint/parser": "^8.48.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -3352,21 +2737,23 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.47.0.tgz", - "integrity": "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz", + "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4" }, "engines": { @@ -3382,13 +2769,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.47.0.tgz", - "integrity": "sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", + "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.47.0", - "@typescript-eslint/types": "^8.47.0", + "@typescript-eslint/tsconfig-utils": "^8.48.0", + "@typescript-eslint/types": "^8.48.0", "debug": "^4.3.4" }, "engines": { @@ -3403,13 +2791,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.47.0.tgz", - "integrity": "sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", + "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0" + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3420,10 +2809,11 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.47.0.tgz", - "integrity": "sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", + "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3436,14 +2826,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.47.0.tgz", - "integrity": "sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", + "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/utils": "8.47.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -3460,10 +2851,11 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.47.0.tgz", - "integrity": "sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz", + "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3473,20 +2865,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.47.0.tgz", - "integrity": "sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", + "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.47.0", - "@typescript-eslint/tsconfig-utils": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", + "@typescript-eslint/project-service": "8.48.0", + "@typescript-eslint/tsconfig-utils": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", + "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "engines": { @@ -3505,6 +2897,7 @@ "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" } @@ -3514,6 +2907,7 @@ "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" }, @@ -3529,6 +2923,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3537,15 +2932,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.47.0.tgz", - "integrity": "sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz", + "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0" + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3560,12 +2956,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.47.0.tgz", - "integrity": "sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", + "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", + "@typescript-eslint/types": "8.48.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -3581,6 +2978,7 @@ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz", "integrity": "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", @@ -3657,6 +3055,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz", "integrity": "sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -3668,6 +3067,7 @@ "version": "0.7.4", "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz", "integrity": "sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -3679,6 +3079,7 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz", "integrity": "sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -3690,6 +3091,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz", "integrity": "sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -3702,6 +3104,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "peer": true, "bin": { "acorn": "bin/acorn" @@ -3715,6 +3118,7 @@ "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" } @@ -3748,6 +3152,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3790,6 +3195,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3832,7 +3238,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-union": { "version": "2.1.0", @@ -3912,57 +3319,12 @@ "postcss": "^8.1.0" } }, - "node_modules/babel-plugin-syntax-trailing-function-commas": { - "version": "7.0.0-beta.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", - "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-preset-fbjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz", - "integrity": "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-syntax-class-properties": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-block-scoped-functions": "^7.0.0", - "@babel/plugin-transform-block-scoping": "^7.0.0", - "@babel/plugin-transform-classes": "^7.0.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-flow-strip-types": "^7.0.0", - "@babel/plugin-transform-for-of": "^7.0.0", - "@babel/plugin-transform-function-name": "^7.0.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-member-expression-literals": "^7.0.0", - "@babel/plugin-transform-modules-commonjs": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.0.0", - "@babel/plugin-transform-parameters": "^7.0.0", - "@babel/plugin-transform-property-literals": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", - "babel-plugin-syntax-trailing-function-commas": "^7.0.0-beta.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -3990,6 +3352,7 @@ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", "dev": true, + "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" } @@ -4024,6 +3387,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4034,6 +3398,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -4060,6 +3425,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", @@ -4115,6 +3481,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4130,16 +3497,6 @@ "tslib": "^2.0.3" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -4151,9 +3508,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001756", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz", - "integrity": "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==", + "version": "1.0.30001757", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", + "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", "dev": true, "funding": [ { @@ -4168,7 +3525,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/capital-case": { "version": "1.0.4", @@ -4187,6 +3545,7 @@ "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" @@ -4415,6 +3774,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -4426,7 +3786,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", @@ -4459,7 +3820,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/constant-case": { "version": "3.0.4", @@ -4477,7 +3839,8 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/cosmiconfig": { "version": "8.3.6", @@ -4534,6 +3897,7 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4560,7 +3924,8 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true + "devOptional": true, + "license": "MIT" }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", @@ -4591,6 +3956,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -4603,21 +3969,12 @@ } } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "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 + "dev": true, + "license": "MIT" }, "node_modules/defaults": { "version": "1.0.4", @@ -4714,10 +4071,11 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.259", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.259.tgz", - "integrity": "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==", - "dev": true + "version": "1.5.260", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.260.tgz", + "integrity": "sha512-ov8rBoOBhVawpzdre+Cmz4FB+y66Eqrk6Gwqd8NGxuhv99GQ8XqMAr351KEkOt7gukXWDg6gJWEMKgL2RLMPtA==", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -4742,6 +4100,7 @@ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -4782,6 +4141,7 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -4791,6 +4151,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4803,6 +4164,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", @@ -4863,6 +4225,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", @@ -4882,6 +4245,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", "dev": true, + "license": "MIT", "peerDependencies": { "eslint": ">=8.40" } @@ -4891,6 +4255,7 @@ "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" @@ -4907,6 +4272,7 @@ "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" }, @@ -4919,6 +4285,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", @@ -4936,6 +4303,7 @@ "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" }, @@ -4948,6 +4316,7 @@ "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" }, @@ -4960,6 +4329,7 @@ "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" } @@ -4969,6 +4339,7 @@ "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" } @@ -4977,13 +4348,15 @@ "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -5000,6 +4373,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5011,19 +4385,22 @@ "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==", - "dev": true + "dev": true, + "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 + "dev": true, + "license": "MIT" }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -5116,6 +4493,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" }, @@ -5128,6 +4506,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5140,6 +4519,7 @@ "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" @@ -5156,6 +4536,7 @@ "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" @@ -5168,7 +4549,8 @@ "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 + "dev": true, + "license": "ISC" }, "node_modules/formdata-polyfill": { "version": "4.0.10", @@ -5197,19 +4579,13 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5233,6 +4609,7 @@ "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" } @@ -5247,33 +4624,12 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -5286,6 +4642,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -5318,12 +4675,14 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/graphql": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", "integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==", + "license": "MIT", "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" @@ -5415,6 +4774,7 @@ "version": "2.12.6", "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" }, @@ -5462,6 +4822,7 @@ "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" } @@ -5494,13 +4855,15 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "dev": true, + "license": "MIT", "dependencies": { "hermes-estree": "0.25.1" } @@ -5576,6 +4939,7 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -5595,6 +4959,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5606,6 +4971,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-fresh/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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/import-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", @@ -5624,6 +4999,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -5638,18 +5014,6 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -5749,6 +5113,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5768,6 +5133,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5800,6 +5166,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5867,7 +5234,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isomorphic-ws": { "version": "5.0.0", @@ -5903,13 +5271,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -5922,6 +5292,7 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -5933,7 +5304,8 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -5946,13 +5318,15 @@ "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==", - "dev": true + "dev": true, + "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 + "dev": true, + "license": "MIT" }, "node_modules/json-to-pretty-yaml": { "version": "1.2.2", @@ -5973,6 +5347,7 @@ "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" }, @@ -5994,6 +5369,7 @@ "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" } @@ -6003,6 +5379,7 @@ "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" @@ -6082,6 +5459,7 @@ "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" }, @@ -6103,7 +5481,8 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/lodash.sortby": { "version": "4.7.0", @@ -6204,6 +5583,7 @@ "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" } @@ -6223,6 +5603,7 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -6250,6 +5631,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -6273,6 +5655,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6284,7 +5667,8 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mute-stream": { "version": "0.0.8", @@ -6316,6 +5700,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -6327,7 +5712,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/no-case": { "version": "3.0.4", @@ -6393,7 +5779,8 @@ "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -6454,16 +5841,6 @@ "node": ">=18" } }, - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -6484,6 +5861,7 @@ "version": "0.18.1", "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.1.tgz", "integrity": "sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==", + "license": "MIT", "dependencies": { "@wry/caches": "^1.0.0", "@wry/context": "^0.7.0", @@ -6496,6 +5874,7 @@ "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", @@ -6537,6 +5916,7 @@ "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" }, @@ -6552,6 +5932,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -6578,16 +5959,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -6604,6 +5975,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -6672,18 +6044,9 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/path-key": { @@ -6691,6 +6054,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6739,13 +6103,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -6792,6 +6158,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "peer": true, "dependencies": { "nanoid": "^3.3.11", @@ -6941,6 +6308,7 @@ "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" } @@ -6960,6 +6328,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6982,12 +6351,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/react": { "version": "19.2.0", "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", "peer": true, "engines": { "node": ">=0.10.0" @@ -6997,6 +6368,7 @@ "version": "19.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", "peer": true, "dependencies": { "scheduler": "^0.27.0" @@ -7010,6 +6382,7 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7130,13 +6503,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true, - "license": "ISC" - }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -7159,12 +6525,13 @@ } }, "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/restore-cursor": { @@ -7186,6 +6553,7 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -7203,6 +6571,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "1.0.8" }, @@ -7268,6 +6637,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -7276,6 +6646,7 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", "peer": true, "dependencies": { "tslib": "^2.1.0" @@ -7312,7 +6683,8 @@ "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/scuid": { "version": "1.1.0", @@ -7326,6 +6698,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -7342,13 +6715,6 @@ "upper-case-first": "^2.0.2" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -7361,6 +6727,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -7373,6 +6740,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7445,6 +6813,7 @@ "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" } @@ -7509,6 +6878,7 @@ "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" }, @@ -7544,6 +6914,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7712,6 +7083,7 @@ "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" @@ -7728,6 +7100,7 @@ "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" }, @@ -7745,6 +7118,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=12" @@ -7768,6 +7142,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -7787,6 +7162,7 @@ "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" }, @@ -7811,13 +7187,15 @@ "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==" + "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" }, @@ -7843,6 +7221,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, + "license": "Apache-2.0", "peer": true, "bin": { "tsc": "bin/tsc", @@ -7853,15 +7232,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.47.0.tgz", - "integrity": "sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.0.tgz", + "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.47.0", - "@typescript-eslint/parser": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/utils": "8.47.0" + "@typescript-eslint/eslint-plugin": "8.48.0", + "@typescript-eslint/parser": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7916,7 +7296,8 @@ "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/unixify": { "version": "1.0.0", @@ -7963,6 +7344,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -7999,6 +7381,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -8022,6 +7405,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "esbuild": "^0.25.0", @@ -8097,6 +7481,7 @@ "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" }, @@ -8114,6 +7499,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=12" @@ -8175,6 +7561,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -8185,18 +7572,12 @@ "node": ">= 8" } }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true, - "license": "ISC" - }, "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" } @@ -8216,13 +7597,6 @@ "node": ">=8" } }, - "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==", - "dev": true, - "license": "ISC" - }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", @@ -8260,7 +7634,8 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yaml": { "version": "2.8.1", @@ -8316,6 +7691,7 @@ "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" }, @@ -8324,10 +7700,11 @@ } }, "node_modules/zod": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", - "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "dev": true, + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -8338,6 +7715,7 @@ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.0.0" }, diff --git a/fictionarchive-web/package.json b/fictionarchive-web/package.json index b314ed6..a7863bc 100644 --- a/fictionarchive-web/package.json +++ b/fictionarchive-web/package.json @@ -6,7 +6,6 @@ "scripts": { "dev": "vite", "build": "tsc -b && vite build", - "prebuild": "npm run codegen", "codegen": "graphql-codegen --config codegen.ts -r dotenv/config --use-system-ca", "lint": "eslint .", "preview": "vite preview" @@ -17,18 +16,18 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "graphql": "^16.12.0", - "react-router-dom": "^6.27.0", "oidc-client-ts": "^3.4.1", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-router-dom": "^6.27.0", "tailwind-merge": "^2.5.4" }, "devDependencies": { + "@eslint/js": "^9.39.1", "@graphql-codegen/cli": "^5.0.3", + "@graphql-codegen/typed-document-node": "^6.1.1", "@graphql-codegen/typescript": "^4.0.9", "@graphql-codegen/typescript-operations": "^4.0.9", - "@graphql-codegen/typescript-react-apollo": "^4.0.9", - "@eslint/js": "^9.39.1", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", diff --git a/fictionarchive-web/src/__generated__/graphql.ts b/fictionarchive-web/src/__generated__/graphql.ts new file mode 100644 index 0000000..1780522 --- /dev/null +++ b/fictionarchive-web/src/__generated__/graphql.ts @@ -0,0 +1,774 @@ +import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +export type Maybe = T | null; +export type InputMaybe = T | null; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + Instant: { input: any; output: any; } + UUID: { input: any; output: any; } + UnsignedInt: { input: any; output: any; } +}; + +export type Chapter = { + body: LocalizationKey; + createdTime: Scalars['Instant']['output']; + id: Scalars['UnsignedInt']['output']; + images: Array; + lastUpdatedTime: Scalars['Instant']['output']; + name: LocalizationKey; + order: Scalars['UnsignedInt']['output']; + revision: Scalars['UnsignedInt']['output']; + url: Maybe; +}; + +export type ChapterFilterInput = { + and?: InputMaybe>; + body?: InputMaybe; + createdTime?: InputMaybe; + id?: InputMaybe; + images?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; + or?: InputMaybe>; + order?: InputMaybe; + revision?: InputMaybe; + url?: InputMaybe; +}; + +export type ChapterPullRequestedEvent = { + chapterNumber: Scalars['UnsignedInt']['output']; + novelId: Scalars['UnsignedInt']['output']; +}; + +export type ChapterSortInput = { + body?: InputMaybe; + createdTime?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; + order?: InputMaybe; + revision?: InputMaybe; + url?: InputMaybe; +}; + +export type DeleteJobError = KeyNotFoundError; + +export type DeleteJobInput = { + jobKey: Scalars['String']['input']; +}; + +export type DeleteJobPayload = { + boolean: Maybe; + errors: Maybe>; +}; + +export type DuplicateNameError = Error & { + message: Scalars['String']['output']; +}; + +export type Error = { + message: Scalars['String']['output']; +}; + +export type FetchChapterContentsInput = { + chapterNumber: Scalars['UnsignedInt']['input']; + novelId: Scalars['UnsignedInt']['input']; +}; + +export type FetchChapterContentsPayload = { + chapterPullRequestedEvent: Maybe; +}; + +export type FormatError = Error & { + message: Scalars['String']['output']; +}; + +export type Image = { + chapter: Maybe; + createdTime: Scalars['Instant']['output']; + id: Scalars['UUID']['output']; + lastUpdatedTime: Scalars['Instant']['output']; + newPath: Maybe; + originalPath: Scalars['String']['output']; +}; + +export type ImageFilterInput = { + and?: InputMaybe>; + chapter?: InputMaybe; + createdTime?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + newPath?: InputMaybe; + or?: InputMaybe>; + originalPath?: InputMaybe; +}; + +export type ImageSortInput = { + chapter?: InputMaybe; + createdTime?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + newPath?: InputMaybe; + originalPath?: InputMaybe; +}; + +export type ImportNovelInput = { + novelUrl: Scalars['String']['input']; +}; + +export type ImportNovelPayload = { + novelUpdateRequestedEvent: Maybe; +}; + +export type InstantFilterInput = { + and?: InputMaybe>; + or?: InputMaybe>; +}; + +export type JobKey = { + group: Scalars['String']['output']; + name: Scalars['String']['output']; +}; + +export type JobPersistenceError = Error & { + message: Scalars['String']['output']; +}; + +export type KeyNotFoundError = Error & { + message: Scalars['String']['output']; +}; + +export type KeyValuePairOfStringAndString = { + key: Scalars['String']['output']; + value: Scalars['String']['output']; +}; + +export const Language = { + Ch: 'CH', + En: 'EN', + Ja: 'JA', + Kr: 'KR' +} as const; + +export type Language = typeof Language[keyof typeof Language]; +export type LanguageOperationFilterInput = { + eq?: InputMaybe; + in?: InputMaybe>; + neq?: InputMaybe; + nin?: InputMaybe>; +}; + +export type ListFilterInputTypeOfChapterFilterInput = { + all?: InputMaybe; + any?: InputMaybe; + none?: InputMaybe; + some?: InputMaybe; +}; + +export type ListFilterInputTypeOfImageFilterInput = { + all?: InputMaybe; + any?: InputMaybe; + none?: InputMaybe; + some?: InputMaybe; +}; + +export type ListFilterInputTypeOfLocalizationTextFilterInput = { + all?: InputMaybe; + any?: InputMaybe; + none?: InputMaybe; + some?: InputMaybe; +}; + +export type ListFilterInputTypeOfNovelFilterInput = { + all?: InputMaybe; + any?: InputMaybe; + none?: InputMaybe; + some?: InputMaybe; +}; + +export type ListFilterInputTypeOfNovelTagFilterInput = { + all?: InputMaybe; + any?: InputMaybe; + none?: InputMaybe; + some?: InputMaybe; +}; + +export type LocalizationKey = { + createdTime: Scalars['Instant']['output']; + id: Scalars['UUID']['output']; + lastUpdatedTime: Scalars['Instant']['output']; + texts: Array; +}; + +export type LocalizationKeyFilterInput = { + and?: InputMaybe>; + createdTime?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + or?: InputMaybe>; + texts?: InputMaybe; +}; + +export type LocalizationKeySortInput = { + createdTime?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; +}; + +export type LocalizationText = { + createdTime: Scalars['Instant']['output']; + id: Scalars['UUID']['output']; + language: Language; + lastUpdatedTime: Scalars['Instant']['output']; + text: Scalars['String']['output']; + translationEngine: Maybe; +}; + +export type LocalizationTextFilterInput = { + and?: InputMaybe>; + createdTime?: InputMaybe; + id?: InputMaybe; + language?: InputMaybe; + lastUpdatedTime?: InputMaybe; + or?: InputMaybe>; + text?: InputMaybe; + translationEngine?: InputMaybe; +}; + +export type Mutation = { + deleteJob: DeleteJobPayload; + fetchChapterContents: FetchChapterContentsPayload; + importNovel: ImportNovelPayload; + registerUser: RegisterUserPayload; + runJob: RunJobPayload; + scheduleEventJob: ScheduleEventJobPayload; + translateText: TranslateTextPayload; +}; + + +export type MutationDeleteJobArgs = { + input: DeleteJobInput; +}; + + +export type MutationFetchChapterContentsArgs = { + input: FetchChapterContentsInput; +}; + + +export type MutationImportNovelArgs = { + input: ImportNovelInput; +}; + + +export type MutationRegisterUserArgs = { + input: RegisterUserInput; +}; + + +export type MutationRunJobArgs = { + input: RunJobInput; +}; + + +export type MutationScheduleEventJobArgs = { + input: ScheduleEventJobInput; +}; + + +export type MutationTranslateTextArgs = { + input: TranslateTextInput; +}; + +export type Novel = { + author: Person; + chapters: Array; + coverImage: Maybe; + createdTime: Scalars['Instant']['output']; + description: LocalizationKey; + externalId: Scalars['String']['output']; + id: Scalars['UnsignedInt']['output']; + lastUpdatedTime: Scalars['Instant']['output']; + name: LocalizationKey; + rawLanguage: Language; + rawStatus: NovelStatus; + source: Source; + statusOverride: Maybe; + tags: Array; + url: Scalars['String']['output']; +}; + +export type NovelFilterInput = { + and?: InputMaybe>; + author?: InputMaybe; + chapters?: InputMaybe; + coverImage?: InputMaybe; + createdTime?: InputMaybe; + description?: InputMaybe; + externalId?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; + or?: InputMaybe>; + rawLanguage?: InputMaybe; + rawStatus?: InputMaybe; + source?: InputMaybe; + statusOverride?: InputMaybe; + tags?: InputMaybe; + url?: InputMaybe; +}; + +export type NovelSortInput = { + author?: InputMaybe; + coverImage?: InputMaybe; + createdTime?: InputMaybe; + description?: InputMaybe; + externalId?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; + rawLanguage?: InputMaybe; + rawStatus?: InputMaybe; + source?: InputMaybe; + statusOverride?: InputMaybe; + url?: InputMaybe; +}; + +export const NovelStatus = { + Abandoned: 'ABANDONED', + Completed: 'COMPLETED', + Hiatus: 'HIATUS', + InProgress: 'IN_PROGRESS', + Unknown: 'UNKNOWN' +} as const; + +export type NovelStatus = typeof NovelStatus[keyof typeof NovelStatus]; +export type NovelStatusOperationFilterInput = { + eq?: InputMaybe; + in?: InputMaybe>; + neq?: InputMaybe; + nin?: InputMaybe>; +}; + +export type NovelTag = { + createdTime: Scalars['Instant']['output']; + displayName: LocalizationKey; + id: Scalars['UnsignedInt']['output']; + key: Scalars['String']['output']; + lastUpdatedTime: Scalars['Instant']['output']; + novels: Array; + source: Maybe; + tagType: TagType; +}; + +export type NovelTagFilterInput = { + and?: InputMaybe>; + createdTime?: InputMaybe; + displayName?: InputMaybe; + id?: InputMaybe; + key?: InputMaybe; + lastUpdatedTime?: InputMaybe; + novels?: InputMaybe; + or?: InputMaybe>; + source?: InputMaybe; + tagType?: InputMaybe; +}; + +export type NovelUpdateRequestedEvent = { + novelUrl: Scalars['String']['output']; +}; + +/** A connection to a list of items. */ +export type NovelsConnection = { + /** A list of edges. */ + edges: Maybe>; + /** A flattened list of the nodes. */ + nodes: Maybe>; + /** Information to aid in pagination. */ + pageInfo: PageInfo; +}; + +/** An edge in a connection. */ +export type NovelsEdge = { + /** A cursor for use in pagination. */ + cursor: Scalars['String']['output']; + /** The item at the end of the edge. */ + node: Novel; +}; + +export type NullableOfNovelStatusOperationFilterInput = { + eq?: InputMaybe; + in?: InputMaybe>>; + neq?: InputMaybe; + nin?: InputMaybe>>; +}; + +/** Information about pagination in a connection. */ +export type PageInfo = { + /** When paginating forwards, the cursor to continue. */ + endCursor: Maybe; + /** Indicates whether more edges exist following the set defined by the clients arguments. */ + hasNextPage: Scalars['Boolean']['output']; + /** Indicates whether more edges exist prior the set defined by the clients arguments. */ + hasPreviousPage: Scalars['Boolean']['output']; + /** When paginating backwards, the cursor to continue. */ + startCursor: Maybe; +}; + +export type Person = { + createdTime: Scalars['Instant']['output']; + externalUrl: Maybe; + id: Scalars['UnsignedInt']['output']; + lastUpdatedTime: Scalars['Instant']['output']; + name: LocalizationKey; +}; + +export type PersonFilterInput = { + and?: InputMaybe>; + createdTime?: InputMaybe; + externalUrl?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; + or?: InputMaybe>; +}; + +export type PersonSortInput = { + createdTime?: InputMaybe; + externalUrl?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; +}; + +export type Query = { + jobs: Array; + novels: Maybe; + translationEngines: Array; + translationRequests: Maybe; + users: Array; +}; + + +export type QueryNovelsArgs = { + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + order?: InputMaybe>; + where?: InputMaybe; +}; + + +export type QueryTranslationEnginesArgs = { + order?: InputMaybe>; + where?: InputMaybe; +}; + + +export type QueryTranslationRequestsArgs = { + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + order?: InputMaybe>; + where?: InputMaybe; +}; + +export type RegisterUserInput = { + email: Scalars['String']['input']; + inviterOAuthProviderId?: InputMaybe; + oAuthProviderId: Scalars['String']['input']; + username: Scalars['String']['input']; +}; + +export type RegisterUserPayload = { + user: Maybe; +}; + +export type RunJobError = JobPersistenceError; + +export type RunJobInput = { + jobKey: Scalars['String']['input']; +}; + +export type RunJobPayload = { + boolean: Maybe; + errors: Maybe>; +}; + +export type ScheduleEventJobError = DuplicateNameError | FormatError; + +export type ScheduleEventJobInput = { + cronSchedule: Scalars['String']['input']; + description: Scalars['String']['input']; + eventData: Scalars['String']['input']; + eventType: Scalars['String']['input']; + key: Scalars['String']['input']; +}; + +export type ScheduleEventJobPayload = { + errors: Maybe>; + schedulerJob: Maybe; +}; + +export type SchedulerJob = { + cronSchedule: Array; + description: Scalars['String']['output']; + jobData: Array; + jobKey: JobKey; + jobTypeName: Scalars['String']['output']; +}; + +export const SortEnumType = { + Asc: 'ASC', + Desc: 'DESC' +} as const; + +export type SortEnumType = typeof SortEnumType[keyof typeof SortEnumType]; +export type Source = { + createdTime: Scalars['Instant']['output']; + id: Scalars['UnsignedInt']['output']; + key: Scalars['String']['output']; + lastUpdatedTime: Scalars['Instant']['output']; + name: Scalars['String']['output']; + url: Scalars['String']['output']; +}; + +export type SourceFilterInput = { + and?: InputMaybe>; + createdTime?: InputMaybe; + id?: InputMaybe; + key?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; + or?: InputMaybe>; + url?: InputMaybe; +}; + +export type SourceSortInput = { + createdTime?: InputMaybe; + id?: InputMaybe; + key?: InputMaybe; + lastUpdatedTime?: InputMaybe; + name?: InputMaybe; + url?: InputMaybe; +}; + +export type StringOperationFilterInput = { + and?: InputMaybe>; + contains?: InputMaybe; + endsWith?: InputMaybe; + eq?: InputMaybe; + in?: InputMaybe>>; + ncontains?: InputMaybe; + nendsWith?: InputMaybe; + neq?: InputMaybe; + nin?: InputMaybe>>; + nstartsWith?: InputMaybe; + or?: InputMaybe>; + startsWith?: InputMaybe; +}; + +export const TagType = { + External: 'EXTERNAL', + Genre: 'GENRE', + System: 'SYSTEM', + UserDefined: 'USER_DEFINED' +} as const; + +export type TagType = typeof TagType[keyof typeof TagType]; +export type TagTypeOperationFilterInput = { + eq?: InputMaybe; + in?: InputMaybe>; + neq?: InputMaybe; + nin?: InputMaybe>; +}; + +export type TranslateTextInput = { + from: Language; + text: Scalars['String']['input']; + to: Language; + translationEngineKey: Scalars['String']['input']; +}; + +export type TranslateTextPayload = { + translationResult: Maybe; +}; + +export type TranslationEngine = { + createdTime: Scalars['Instant']['output']; + id: Scalars['UnsignedInt']['output']; + key: Scalars['String']['output']; + lastUpdatedTime: Scalars['Instant']['output']; +}; + +export type TranslationEngineDescriptor = { + displayName: Scalars['String']['output']; + key: Scalars['String']['output']; +}; + +export type TranslationEngineDescriptorFilterInput = { + and?: InputMaybe>; + displayName?: InputMaybe; + key?: InputMaybe; + or?: InputMaybe>; +}; + +export type TranslationEngineDescriptorSortInput = { + displayName?: InputMaybe; + key?: InputMaybe; +}; + +export type TranslationEngineFilterInput = { + and?: InputMaybe>; + createdTime?: InputMaybe; + id?: InputMaybe; + key?: InputMaybe; + lastUpdatedTime?: InputMaybe; + or?: InputMaybe>; +}; + +export type TranslationRequest = { + billedCharacterCount: Scalars['UnsignedInt']['output']; + createdTime: Scalars['Instant']['output']; + from: Language; + id: Scalars['UUID']['output']; + lastUpdatedTime: Scalars['Instant']['output']; + originalText: Scalars['String']['output']; + status: TranslationRequestStatus; + to: Language; + translatedText: Maybe; + translationEngineKey: Scalars['String']['output']; +}; + +export type TranslationRequestFilterInput = { + and?: InputMaybe>; + billedCharacterCount?: InputMaybe; + createdTime?: InputMaybe; + from?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + or?: InputMaybe>; + originalText?: InputMaybe; + status?: InputMaybe; + to?: InputMaybe; + translatedText?: InputMaybe; + translationEngineKey?: InputMaybe; +}; + +export type TranslationRequestSortInput = { + billedCharacterCount?: InputMaybe; + createdTime?: InputMaybe; + from?: InputMaybe; + id?: InputMaybe; + lastUpdatedTime?: InputMaybe; + originalText?: InputMaybe; + status?: InputMaybe; + to?: InputMaybe; + translatedText?: InputMaybe; + translationEngineKey?: InputMaybe; +}; + +export const TranslationRequestStatus = { + Failed: 'FAILED', + Pending: 'PENDING', + Success: 'SUCCESS' +} as const; + +export type TranslationRequestStatus = typeof TranslationRequestStatus[keyof typeof TranslationRequestStatus]; +export type TranslationRequestStatusOperationFilterInput = { + eq?: InputMaybe; + in?: InputMaybe>; + neq?: InputMaybe; + nin?: InputMaybe>; +}; + +/** A connection to a list of items. */ +export type TranslationRequestsConnection = { + /** A list of edges. */ + edges: Maybe>; + /** A flattened list of the nodes. */ + nodes: Maybe>; + /** Information to aid in pagination. */ + pageInfo: PageInfo; +}; + +/** An edge in a connection. */ +export type TranslationRequestsEdge = { + /** A cursor for use in pagination. */ + cursor: Scalars['String']['output']; + /** The item at the end of the edge. */ + node: TranslationRequest; +}; + +export type TranslationResult = { + billedCharacterCount: Scalars['UnsignedInt']['output']; + from: Language; + originalText: Scalars['String']['output']; + status: TranslationRequestStatus; + to: Language; + translatedText: Maybe; + translationEngineKey: Scalars['String']['output']; +}; + +export type UnsignedIntOperationFilterInputType = { + eq?: InputMaybe; + gt?: InputMaybe; + gte?: InputMaybe; + in?: InputMaybe>>; + lt?: InputMaybe; + lte?: InputMaybe; + neq?: InputMaybe; + ngt?: InputMaybe; + ngte?: InputMaybe; + nin?: InputMaybe>>; + nlt?: InputMaybe; + nlte?: InputMaybe; +}; + +export type User = { + createdTime: Scalars['Instant']['output']; + disabled: Scalars['Boolean']['output']; + email: Scalars['String']['output']; + id: Scalars['UUID']['output']; + inviter: Maybe; + lastUpdatedTime: Scalars['Instant']['output']; + oAuthProviderId: Scalars['String']['output']; + username: Scalars['String']['output']; +}; + +export type UuidOperationFilterInput = { + eq?: InputMaybe; + gt?: InputMaybe; + gte?: InputMaybe; + in?: InputMaybe>>; + lt?: InputMaybe; + lte?: InputMaybe; + neq?: InputMaybe; + ngt?: InputMaybe; + ngte?: InputMaybe; + nin?: InputMaybe>>; + nlt?: InputMaybe; + nlte?: InputMaybe; +}; + +export type NovelsQueryVariables = Exact<{ + first?: InputMaybe; + after?: InputMaybe; +}>; + + +export type NovelsQuery = { novels: { edges: Array<{ cursor: string, node: { id: any, url: string, name: { texts: Array<{ language: Language, text: string }> }, description: { texts: Array<{ language: Language, text: string }> }, coverImage: { originalPath: string, newPath: string | null } | null } }> | null, pageInfo: { hasNextPage: boolean, endCursor: string | null } } | null }; + + +export const NovelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Novels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"after"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"novels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"after"},"value":{"kind":"Variable","name":{"kind":"Name","value":"after"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"name"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"texts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"text"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"description"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"texts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"language"}},{"kind":"Field","name":{"kind":"Name","value":"text"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"coverImage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"originalPath"}},{"kind":"Field","name":{"kind":"Name","value":"newPath"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/fictionarchive-web/src/apolloClient.ts b/fictionarchive-web/src/apolloClient.ts index 1bc87ed..058e4e0 100644 --- a/fictionarchive-web/src/apolloClient.ts +++ b/fictionarchive-web/src/apolloClient.ts @@ -6,7 +6,7 @@ const uri = import.meta.env.VITE_GRAPHQL_URI ?? 'https://localhost:5001/graphql' const httpLink = new HttpLink({ uri }) -const authLink = new SetContextLink(async ({ headers }, _) => { +const authLink = new SetContextLink(async ({ headers }) => { if (!userManager) return { headers } try { const user = await userManager.getUser() diff --git a/fictionarchive-web/src/auth/AuthContext.tsx b/fictionarchive-web/src/auth/AuthContext.tsx index d3d781d..6ccb637 100644 --- a/fictionarchive-web/src/auth/AuthContext.tsx +++ b/fictionarchive-web/src/auth/AuthContext.tsx @@ -14,12 +14,11 @@ const AuthContext = createContext(undefined) export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null) - const [isLoading, setIsLoading] = useState(true) + const [isLoading, setIsLoading] = useState(!!userManager) const callbackHandledRef = useRef(false) useEffect(() => { if (!userManager) { - setIsLoading(false) return } @@ -121,6 +120,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { return {children} } +// eslint-disable-next-line react-refresh/only-export-components export function useAuth() { const context = useContext(AuthContext) if (!context) { diff --git a/fictionarchive-web/src/components/NovelCard.tsx b/fictionarchive-web/src/components/NovelCard.tsx index 4a5db75..5f3a807 100644 --- a/fictionarchive-web/src/components/NovelCard.tsx +++ b/fictionarchive-web/src/components/NovelCard.tsx @@ -1,11 +1,13 @@ -import type { Novel } from '../__generated__/graphql' +import type { NovelsQuery } from '../__generated__/graphql' import { Card, CardContent, CardHeader, CardTitle } from './ui/card' +type NovelNode = NonNullable['edges']>[number]['node'] + type NovelCardProps = { - novel: Novel + novel: NovelNode } -function pickText(novelText?: Novel['name'] | Novel['description']) { +function pickText(novelText?: NovelNode['name'] | NovelNode['description']) { const texts = novelText?.texts ?? [] const english = texts.find((t) => t.language === 'EN') return (english ?? texts[0])?.text ?? 'No description available.' diff --git a/fictionarchive-web/src/components/ui/badge.tsx b/fictionarchive-web/src/components/ui/badge.tsx index 8cf516f..fa47ef3 100644 --- a/fictionarchive-web/src/components/ui/badge.tsx +++ b/fictionarchive-web/src/components/ui/badge.tsx @@ -31,4 +31,5 @@ function Badge({ className, variant, ...props }: BadgeProps) { ) } +// eslint-disable-next-line react-refresh/only-export-components export { Badge, badgeVariants } diff --git a/fictionarchive-web/src/components/ui/button.tsx b/fictionarchive-web/src/components/ui/button.tsx index fb25275..ab026f2 100644 --- a/fictionarchive-web/src/components/ui/button.tsx +++ b/fictionarchive-web/src/components/ui/button.tsx @@ -51,4 +51,5 @@ const Button = React.forwardRef( ) Button.displayName = 'Button' +// eslint-disable-next-line react-refresh/only-export-components export { Button, buttonVariants } diff --git a/fictionarchive-web/src/components/ui/input.tsx b/fictionarchive-web/src/components/ui/input.tsx index dfff7a2..3e75349 100644 --- a/fictionarchive-web/src/components/ui/input.tsx +++ b/fictionarchive-web/src/components/ui/input.tsx @@ -2,8 +2,7 @@ import * as React from 'react' import { cn } from '../../lib/utils' -export interface InputProps - extends React.InputHTMLAttributes {} +export type InputProps = React.InputHTMLAttributes const Input = React.forwardRef( ({ className, type, ...props }, ref) => { diff --git a/fictionarchive-web/src/pages/NovelsPage.tsx b/fictionarchive-web/src/pages/NovelsPage.tsx index 1b56ef5..e93208f 100644 --- a/fictionarchive-web/src/pages/NovelsPage.tsx +++ b/fictionarchive-web/src/pages/NovelsPage.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react' -import { useNovelsQuery } from '../__generated__/graphql' +import { useQuery } from '@apollo/client/react' +import { NovelsDocument } from '../__generated__/graphql' import { NovelCard } from '../components/NovelCard' import { Button } from '../components/ui/button' import { Card, CardContent, CardHeader, CardTitle } from '../components/ui/card' @@ -8,19 +9,18 @@ import { Card, CardContent, CardHeader, CardTitle } from '../components/ui/card' const PAGE_SIZE = 12 export function NovelsPage() { - const { data, loading, error, fetchMore } = useNovelsQuery({ + const { data, loading, error, fetchMore } = useQuery(NovelsDocument, { variables: { first: PAGE_SIZE, after: null }, notifyOnNetworkStatusChange: true, }) - const edges = data?.novels?.edges ?? [] const pageInfo = data?.novels?.pageInfo const hasNextPage = pageInfo?.hasNextPage ?? false const endCursor = pageInfo?.endCursor ?? null const novels = useMemo( - () => edges.map((edge) => edge?.node).filter(Boolean), - [edges] + () => (data?.novels?.edges ?? []).map((edge) => edge?.node).filter(Boolean), + [data?.novels?.edges] ) async function handleLoadMore() {