From 62912e928ad316518df3fb55b098f70837b0a470 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Thu, 28 May 2026 23:59:00 +0200 Subject: [PATCH 01/13] add base github actions file --- .github/workflows/ci.yml | 417 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..074f7c0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,417 @@ +# ───────────────────────────────────────────────────────────────────────────── +# CONCETTI BASE DI GITHUB ACTIONS +# +# Workflow = file YAML in .github/workflows/ — equivalente alla pipeline GitLab +# Job = unità di esecuzione che gira su un runner (VM) — equivalente al job GitLab +# Step = singolo comando dentro un job — equivalente a una riga di "script:" +# Action = step riutilizzabile pubblicato su GitHub Marketplace (es. actions/checkout) +# +# DIFFERENZE CHIAVE rispetto a GitLab CI: +# - Non esistono "stage" espliciti: l'ordine si controlla con "needs:" +# - Ogni job gira su una VM FRESCA (non c'è stato condiviso automaticamente) +# - La cache si gestisce con actions/cache (non è automatica come in GitLab) +# - Gli artifact si passano con actions/upload-artifact / download-artifact +# - I "services" (es. postgres) si definiscono dentro il job con "services:" +# ───────────────────────────────────────────────────────────────────────────── + +# Nome del workflow — appare nell'interfaccia GitHub Actions +name: CI + +# ───────────────────────────────────────────────────────────────────────────── +# ON: TRIGGER — quando parte il workflow +# +# push: ogni push su questi branch +# pull_request: ogni PR aperta/aggiornata verso questi branch +# workflow_dispatch: permette di avviare manualmente dal sito GitHub +# ───────────────────────────────────────────────────────────────────────────── +on: + push: + branches: + - main + - develop + pull_request: + branches: + - main + - develop + workflow_dispatch: # avvio manuale dalla UI di GitHub + +# ───────────────────────────────────────────────────────────────────────────── +# VARIABILI D'AMBIENTE GLOBALI +# Disponibili in tutti i job come env var +# ───────────────────────────────────────────────────────────────────────────── +env: + NODE_ENV: test + NEXT_TELEMETRY_DISABLED: "1" + TURBO_TELEMETRY_DISABLED: "1" + PNPM_VERSION: "9.14.4" + NODE_VERSION: "22" + +# ───────────────────────────────────────────────────────────────────────────── +# JOBS +# Ogni job gira su una VM indipendente (ubuntu-latest = Ubuntu 24.04). +# Per parallelizzare: definisci più job senza "needs:" tra loro. +# Per sequenzializzare: usa "needs: [job-name]". +# +# GitLab "stage" → GitHub Actions "needs" +# GitLab: tutti i job nello stesso stage girano in parallelo +# GitHub: job senza "needs" comune girano in parallelo automaticamente +# ───────────────────────────────────────────────────────────────────────────── +jobs: + + # ───────────────────────────────────────────────────────────────────────── + # JOB 1: install + # Installa le dipendenze e salva la cache per i job successivi. + # + # In GitLab questo era lo stage "setup" con policy: push. + # Qui non esiste "policy": usiamo actions/cache che gestisce tutto. + # ───────────────────────────────────────────────────────────────────────── + install: + name: Install dependencies + runs-on: ubuntu-latest # runner GitHub-hosted (gratuito per repo pubblici) + + steps: + # ── actions/checkout ────────────────────────────────────────────────── + # Clona il repo nella VM. SEMPRE il primo step. + # "with: fetch-depth: 1" = shallow clone, più veloce (default già 1) + - name: Checkout repository + uses: actions/checkout@v4 + + # ── actions/setup-node ──────────────────────────────────────────────── + # Installa Node.js. Più efficiente di installarlo a mano con apt. + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + # ── pnpm/action-setup ───────────────────────────────────────────────── + # Action ufficiale pnpm. Installa pnpm e abilita corepack automaticamente. + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + # ── actions/cache ───────────────────────────────────────────────────── + # Salva/ripristina la cache del pnpm store. + # + # key: stringa univoca per questa cache. Se cambia il lockfile → miss. + # restore-keys: fallback se key non esiste (usa cache parziale). + # path: cosa viene cached. Lo store pnpm è fuori dal progetto. + - name: Cache pnpm store + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + # ── actions/upload-artifact ─────────────────────────────────────────── + # Salva file da passare ad altri job. + # DIFFERENZA IMPORTANTE vs GitLab: + # GitLab artifacts sono automatici tra job dello stesso stage. + # GitHub: devi esplicitamente fare upload + download tra job. + # + # Qui salviamo node_modules perché la cache non è garantita al 100%. + # I job successivi faranno "download-artifact" per averli. + - name: Upload node_modules artifact + uses: actions/upload-artifact@v4 + with: + name: node-modules + path: | + node_modules + apps/web/node_modules + apps/customer-service/node_modules + packages/database/node_modules + packages/shared/node_modules + retention-days: 1 # artifact temporaneo, serve solo per questa pipeline + + # ───────────────────────────────────────────────────────────────────────── + # JOB 2: lint + # Equivalente al job "lint" nello stage "validate" di GitLab. + # Gira in parallelo a "typecheck" perché entrambi dipendono solo da "install". + # ───────────────────────────────────────────────────────────────────────── + lint: + name: Lint + runs-on: ubuntu-latest + needs: [install] # aspetta che "install" finisca — come "needs: [install]" in GitLab + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Restore pnpm cache + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- + + # ── download-artifact ───────────────────────────────────────────────── + # Scarica i node_modules caricati dal job "install". + # Senza questo step, la VM non ha node_modules e pnpm install riparte. + - name: Download node_modules + uses: actions/download-artifact@v4 + with: + name: node-modules + + - name: Lint + run: pnpm lint + + # ───────────────────────────────────────────────────────────────────────── + # JOB 3: typecheck + # Gira in parallelo a "lint" (stesso "needs: [install]"). + # ───────────────────────────────────────────────────────────────────────── + typecheck: + name: Typecheck + runs-on: ubuntu-latest + needs: [install] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Restore pnpm cache + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- + + - name: Download node_modules + uses: actions/download-artifact@v4 + with: + name: node-modules + + - name: Typecheck + run: pnpm typecheck + + # ───────────────────────────────────────────────────────────────────────── + # JOB 4: build + # Aspetta che lint E typecheck passino — come in GitLab dove lo stage "build" + # parte solo dopo che lo stage "validate" è completato. + # ───────────────────────────────────────────────────────────────────────── + build: + name: Build + runs-on: ubuntu-latest + needs: [lint, typecheck] # aspetta ENTRAMBI + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Restore pnpm cache + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- + + - name: Download node_modules + uses: actions/download-artifact@v4 + with: + name: node-modules + + - name: Build all packages + run: pnpm build + + # Salva i build artifact per i job di test + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-output + path: | + apps/web/.next + apps/customer-service/dist + packages/database/node_modules/.prisma + retention-days: 1 + + # ───────────────────────────────────────────────────────────────────────── + # JOB 5: test-unit + # Unit test — gira dopo il build. + # ───────────────────────────────────────────────────────────────────────── + test-unit-customer-service: + name: Customer Service Unit Tests + runs-on: ubuntu-latest + needs: [build] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Restore pnpm cache + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- + + - name: Download node_modules + uses: actions/download-artifact@v4 + with: + name: node-modules + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-output + + - name: Run unit tests + run: pnpm --filter customer-service test + + # ───────────────────────────────────────────────────────────────────────── + # JOB 6: test-e2e + # E2E test con PostgreSQL come service container. + # + # "services:" in GitHub Actions = identico a "services:" in GitLab CI. + # Il container postgres è raggiungibile via "localhost" (non tramite alias). + # DIFFERENZA: GitLab usa l'alias come hostname; GitHub usa sempre "localhost". + # ───────────────────────────────────────────────────────────────────────── + test-e2e: + name: E2E Tests + runs-on: ubuntu-latest + needs: [build] + + # ── services ────────────────────────────────────────────────────────── + # Container aggiuntivi che girano accanto al job. + # GitHub li avvia prima di eseguire i "steps". + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_DB: notebook_test + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + # options: comandi docker run aggiuntivi + # --health-cmd: GitHub aspetta che il container sia "healthy" prima di procedere + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 # mappa porta container → host (necessario su GitHub, non su GitLab) + + env: + DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/notebook_test" + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Restore pnpm cache + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- + + - name: Download node_modules + uses: actions/download-artifact@v4 + with: + name: node-modules + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-output + + - name: Run E2E tests + run: pnpm --filter customer-service test:e2e + continue-on-error: true # equivalente a "allow_failure: true" in GitLab + + # ───────────────────────────────────────────────────────────────────────── + # JOB 7: security-audit + # Audit dipendenze. "needs: [install]" — non serve aspettare il build. + # ───────────────────────────────────────────────────────────────────────── + security-audit: + name: Security Audit + runs-on: ubuntu-latest + needs: [install] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Restore pnpm cache + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + pnpm-${{ runner.os }}- + + - name: Download node_modules + uses: actions/download-artifact@v4 + with: + name: node-modules + + - name: Audit dependencies + run: pnpm audit --audit-level=high + continue-on-error: true # vulnerabilità devDependencies non bloccano From 6f0f684bfdf6671021c5dff1095ff55f66f80cc6 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 29 May 2026 00:00:57 +0200 Subject: [PATCH 02/13] let the pipeline run in feature branches --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 074f7c0..c3cfc94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,10 +29,12 @@ on: branches: - main - develop + - feature/** # tutte le feature branch (opzionale, dipende dal tuo workflow) pull_request: branches: - main - develop + - feature/** # tutte le feature branch (opzionale, dipende dal tuo workflow) workflow_dispatch: # avvio manuale dalla UI di GitHub # ───────────────────────────────────────────────────────────────────────────── From de9aafa0b55d982b81325b792e4232cb540cdf09 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 29 May 2026 00:08:54 +0200 Subject: [PATCH 03/13] fix turbo not found error --- .github/workflows/ci.yml | 217 +++++++++++++-------------------------- 1 file changed, 69 insertions(+), 148 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3cfc94..7ea7e3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,15 +14,10 @@ # - I "services" (es. postgres) si definiscono dentro il job con "services:" # ───────────────────────────────────────────────────────────────────────────── -# Nome del workflow — appare nell'interfaccia GitHub Actions name: CI # ───────────────────────────────────────────────────────────────────────────── -# ON: TRIGGER — quando parte il workflow -# -# push: ogni push su questi branch -# pull_request: ogni PR aperta/aggiornata verso questi branch -# workflow_dispatch: permette di avviare manualmente dal sito GitHub +# ON: TRIGGER # ───────────────────────────────────────────────────────────────────────────── on: push: @@ -34,13 +29,9 @@ on: branches: - main - develop - - feature/** # tutte le feature branch (opzionale, dipende dal tuo workflow) - workflow_dispatch: # avvio manuale dalla UI di GitHub + - feature/** + workflow_dispatch: -# ───────────────────────────────────────────────────────────────────────────── -# VARIABILI D'AMBIENTE GLOBALI -# Disponibili in tutti i job come env var -# ───────────────────────────────────────────────────────────────────────────── env: NODE_ENV: test NEXT_TELEMETRY_DISABLED: "1" @@ -49,95 +40,40 @@ env: NODE_VERSION: "22" # ───────────────────────────────────────────────────────────────────────────── -# JOBS -# Ogni job gira su una VM indipendente (ubuntu-latest = Ubuntu 24.04). -# Per parallelizzare: definisci più job senza "needs:" tra loro. -# Per sequenzializzare: usa "needs: [job-name]". +# PERCHÉ NON PASSIAMO node_modules COME ARTIFACT? +# +# actions/upload-artifact zippa i file ma NON preserva i permessi eseguibili. +# I binari in node_modules/.bin/ (turbo, eslint, tsc, ecc.) diventano +# file normali → "command not found" quando provi a eseguirli. # -# GitLab "stage" → GitHub Actions "needs" -# GitLab: tutti i job nello stesso stage girano in parallelo -# GitHub: job senza "needs" comune girano in parallelo automaticamente +# SOLUZIONE: ogni job fa "pnpm install --frozen-lockfile" da solo. +# È veloce perché actions/cache salva lo store pnpm (~/.pnpm-store) che +# contiene i pacchetti già scaricati. pnpm ricrea node_modules in secondi +# senza ri-scaricare nulla dalla rete. +# +# ECCEZIONE: i build artifact (apps/web/.next, dist/, .prisma) NON sono +# binari con permessi speciali, quindi si possono passare tranquillamente. # ───────────────────────────────────────────────────────────────────────────── + jobs: # ───────────────────────────────────────────────────────────────────────── - # JOB 1: install - # Installa le dipendenze e salva la cache per i job successivi. + # ANCHOR YAML PER SETUP COMUNE + # GitHub Actions non supporta YAML anchors (&/*) nativamente. + # L'approccio standard è ripetere i step di setup in ogni job + # (oppure usare "composite actions" in file separati per DRY avanzato). # - # In GitLab questo era lo stage "setup" con policy: push. - # Qui non esiste "policy": usiamo actions/cache che gestisce tutto. + # Qui commentiamo il pattern una volta e lo ripetiamo — è normale in GHA. # ───────────────────────────────────────────────────────────────────────── - install: - name: Install dependencies - runs-on: ubuntu-latest # runner GitHub-hosted (gratuito per repo pubblici) - - steps: - # ── actions/checkout ────────────────────────────────────────────────── - # Clona il repo nella VM. SEMPRE il primo step. - # "with: fetch-depth: 1" = shallow clone, più veloce (default già 1) - - name: Checkout repository - uses: actions/checkout@v4 - - # ── actions/setup-node ──────────────────────────────────────────────── - # Installa Node.js. Più efficiente di installarlo a mano con apt. - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - - # ── pnpm/action-setup ───────────────────────────────────────────────── - # Action ufficiale pnpm. Installa pnpm e abilita corepack automaticamente. - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - - # ── actions/cache ───────────────────────────────────────────────────── - # Salva/ripristina la cache del pnpm store. - # - # key: stringa univoca per questa cache. Se cambia il lockfile → miss. - # restore-keys: fallback se key non esiste (usa cache parziale). - # path: cosa viene cached. Lo store pnpm è fuori dal progetto. - - name: Cache pnpm store - uses: actions/cache@v4 - with: - path: ~/.pnpm-store - key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: | - pnpm-${{ runner.os }}- - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - # ── actions/upload-artifact ─────────────────────────────────────────── - # Salva file da passare ad altri job. - # DIFFERENZA IMPORTANTE vs GitLab: - # GitLab artifacts sono automatici tra job dello stesso stage. - # GitHub: devi esplicitamente fare upload + download tra job. - # - # Qui salviamo node_modules perché la cache non è garantita al 100%. - # I job successivi faranno "download-artifact" per averli. - - name: Upload node_modules artifact - uses: actions/upload-artifact@v4 - with: - name: node-modules - path: | - node_modules - apps/web/node_modules - apps/customer-service/node_modules - packages/database/node_modules - packages/shared/node_modules - retention-days: 1 # artifact temporaneo, serve solo per questa pipeline # ───────────────────────────────────────────────────────────────────────── - # JOB 2: lint - # Equivalente al job "lint" nello stage "validate" di GitLab. - # Gira in parallelo a "typecheck" perché entrambi dipendono solo da "install". + # JOB 1: lint + # Non ha "needs:" → parte subito. Stesso per "typecheck". + # I due job girano in PARALLELO perché non si aspettano a vicenda. # ───────────────────────────────────────────────────────────────────────── lint: name: Lint runs-on: ubuntu-latest - needs: [install] # aspetta che "install" finisca — come "needs: [install]" in GitLab steps: - name: Checkout repository @@ -153,7 +89,11 @@ jobs: with: version: ${{ env.PNPM_VERSION }} - - name: Restore pnpm cache + # ── Cache dello store pnpm ───────────────────────────────────────────── + # ~/.pnpm-store contiene i pacchetti scaricati (come la cache di npm/yarn). + # Se la cache esiste: pnpm install non scarica nulla dalla rete. + # Se non esiste (prima run o lockfile cambiato): scarica tutto e salva. + - name: Cache pnpm store uses: actions/cache@v4 with: path: ~/.pnpm-store @@ -161,25 +101,20 @@ jobs: restore-keys: | pnpm-${{ runner.os }}- - # ── download-artifact ───────────────────────────────────────────────── - # Scarica i node_modules caricati dal job "install". - # Senza questo step, la VM non ha node_modules e pnpm install riparte. - - name: Download node_modules - uses: actions/download-artifact@v4 - with: - name: node-modules + # pnpm ricrea node_modules dallo store locale — in genere < 30 secondi + - name: Install dependencies + run: pnpm install --frozen-lockfile - name: Lint run: pnpm lint # ───────────────────────────────────────────────────────────────────────── - # JOB 3: typecheck - # Gira in parallelo a "lint" (stesso "needs: [install]"). + # JOB 2: typecheck + # Parallelo a "lint" — nessun "needs:", parte contemporaneamente. # ───────────────────────────────────────────────────────────────────────── typecheck: name: Typecheck runs-on: ubuntu-latest - needs: [install] steps: - name: Checkout repository @@ -195,7 +130,7 @@ jobs: with: version: ${{ env.PNPM_VERSION }} - - name: Restore pnpm cache + - name: Cache pnpm store uses: actions/cache@v4 with: path: ~/.pnpm-store @@ -203,23 +138,21 @@ jobs: restore-keys: | pnpm-${{ runner.os }}- - - name: Download node_modules - uses: actions/download-artifact@v4 - with: - name: node-modules + - name: Install dependencies + run: pnpm install --frozen-lockfile - name: Typecheck run: pnpm typecheck # ───────────────────────────────────────────────────────────────────────── - # JOB 4: build - # Aspetta che lint E typecheck passino — come in GitLab dove lo stage "build" - # parte solo dopo che lo stage "validate" è completato. + # JOB 3: build + # "needs: [lint, typecheck]" = aspetta che ENTRAMBI passino. + # Se uno fallisce, questo job non parte (e non spreca minuti di runner). # ───────────────────────────────────────────────────────────────────────── build: name: Build runs-on: ubuntu-latest - needs: [lint, typecheck] # aspetta ENTRAMBI + needs: [lint, typecheck] steps: - name: Checkout repository @@ -235,7 +168,7 @@ jobs: with: version: ${{ env.PNPM_VERSION }} - - name: Restore pnpm cache + - name: Cache pnpm store uses: actions/cache@v4 with: path: ~/.pnpm-store @@ -243,15 +176,16 @@ jobs: restore-keys: | pnpm-${{ runner.os }}- - - name: Download node_modules - uses: actions/download-artifact@v4 - with: - name: node-modules + - name: Install dependencies + run: pnpm install --frozen-lockfile - name: Build all packages run: pnpm build - # Salva i build artifact per i job di test + # ── Build artifact ──────────────────────────────────────────────────── + # Questi file NON sono eseguibili con permessi speciali: si possono + # passare come artifact senza problemi di permessi. + # I job di test li scaricano per non dover rifare il build. - name: Upload build artifacts uses: actions/upload-artifact@v4 with: @@ -263,11 +197,10 @@ jobs: retention-days: 1 # ───────────────────────────────────────────────────────────────────────── - # JOB 5: test-unit - # Unit test — gira dopo il build. + # JOB 4: test-unit # ───────────────────────────────────────────────────────────────────────── - test-unit-customer-service: - name: Customer Service Unit Tests + test-unit: + name: Unit Tests runs-on: ubuntu-latest needs: [build] @@ -285,7 +218,7 @@ jobs: with: version: ${{ env.PNPM_VERSION }} - - name: Restore pnpm cache + - name: Cache pnpm store uses: actions/cache@v4 with: path: ~/.pnpm-store @@ -293,10 +226,8 @@ jobs: restore-keys: | pnpm-${{ runner.os }}- - - name: Download node_modules - uses: actions/download-artifact@v4 - with: - name: node-modules + - name: Install dependencies + run: pnpm install --frozen-lockfile - name: Download build artifacts uses: actions/download-artifact@v4 @@ -307,21 +238,18 @@ jobs: run: pnpm --filter customer-service test # ───────────────────────────────────────────────────────────────────────── - # JOB 6: test-e2e - # E2E test con PostgreSQL come service container. + # JOB 5: test-e2e + # Parallelo a "test-unit" (stesso "needs: [build]"). # - # "services:" in GitHub Actions = identico a "services:" in GitLab CI. - # Il container postgres è raggiungibile via "localhost" (non tramite alias). - # DIFFERENZA: GitLab usa l'alias come hostname; GitHub usa sempre "localhost". + # DIFFERENZA HOSTNAME SERVICES: + # GitLab: "alias: postgres" → hostname "postgres" + # GitHub: sempre "localhost" (+ ports: mapping obbligatorio) # ───────────────────────────────────────────────────────────────────────── test-e2e: name: E2E Tests runs-on: ubuntu-latest needs: [build] - # ── services ────────────────────────────────────────────────────────── - # Container aggiuntivi che girano accanto al job. - # GitHub li avvia prima di eseguire i "steps". services: postgres: image: postgres:16-alpine @@ -329,15 +257,13 @@ jobs: POSTGRES_DB: notebook_test POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres - # options: comandi docker run aggiuntivi - # --health-cmd: GitHub aspetta che il container sia "healthy" prima di procedere options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - - 5432:5432 # mappa porta container → host (necessario su GitHub, non su GitLab) + - 5432:5432 env: DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/notebook_test" @@ -356,7 +282,7 @@ jobs: with: version: ${{ env.PNPM_VERSION }} - - name: Restore pnpm cache + - name: Cache pnpm store uses: actions/cache@v4 with: path: ~/.pnpm-store @@ -364,10 +290,8 @@ jobs: restore-keys: | pnpm-${{ runner.os }}- - - name: Download node_modules - uses: actions/download-artifact@v4 - with: - name: node-modules + - name: Install dependencies + run: pnpm install --frozen-lockfile - name: Download build artifacts uses: actions/download-artifact@v4 @@ -379,13 +303,12 @@ jobs: continue-on-error: true # equivalente a "allow_failure: true" in GitLab # ───────────────────────────────────────────────────────────────────────── - # JOB 7: security-audit - # Audit dipendenze. "needs: [install]" — non serve aspettare il build. + # JOB 6: security-audit + # Parte in parallelo a lint/typecheck — non serve aspettare il build. # ───────────────────────────────────────────────────────────────────────── security-audit: name: Security Audit runs-on: ubuntu-latest - needs: [install] steps: - name: Checkout repository @@ -401,7 +324,7 @@ jobs: with: version: ${{ env.PNPM_VERSION }} - - name: Restore pnpm cache + - name: Cache pnpm store uses: actions/cache@v4 with: path: ~/.pnpm-store @@ -409,11 +332,9 @@ jobs: restore-keys: | pnpm-${{ runner.os }}- - - name: Download node_modules - uses: actions/download-artifact@v4 - with: - name: node-modules + - name: Install dependencies + run: pnpm install --frozen-lockfile - name: Audit dependencies run: pnpm audit --audit-level=high - continue-on-error: true # vulnerabilità devDependencies non bloccano + continue-on-error: true From af1c7e2f77a41344f9bfd0d45d60d4c36b6d2bf2 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 29 May 2026 00:11:25 +0200 Subject: [PATCH 04/13] add typecheck turbo --- turbo.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/turbo.json b/turbo.json index 23c9b39..c88110d 100644 --- a/turbo.json +++ b/turbo.json @@ -48,6 +48,9 @@ "format": { "outputs": ["node_modules/.cache/.prettiercache"] }, + "typecheck": { + "dependsOn": ["^build"] + }, "lint": { "outputs": ["node_modules/.cache/.eslintcache"] }, From 39cf4742f14ad9fe882596066613bd928f049cbc Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 29 May 2026 00:15:04 +0200 Subject: [PATCH 05/13] fix typecheck --- packages/database/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/database/package.json b/packages/database/package.json index 8f3391a..5bba22e 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -8,7 +8,7 @@ "dev": "pnpm with-env prisma", "build": "pnpm with-env prisma generate && tsc -p tsconfig.build.json", "clean": "git clean -xdf .turbo dist node_modules", - "typecheck": "tsc --noEmit", + "typecheck": "prisma generate && tsc --noEmit", "lint": "eslint *.ts*", "lint:fix": "eslint --fix .", "db:build": "pnpm build", From 94f67d1b533b965fa6e9ccd61f6e78a96c6e8ac0 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Thu, 4 Jun 2026 21:00:19 +0200 Subject: [PATCH 06/13] add unit tests for customer service --- CLAUDE.md | 95 +++++++ .../src/auth/auth.service.spec.ts | 260 ++++++++++++++++++ .../src/clients/clients.service.spec.ts | 179 ++++++++++++ .../src/visits/visits.service.spec.ts | 256 +++++++++++++++++ apps/customer-service/tsconfig.json | 4 +- pnpm-lock.yaml | 10 +- 6 files changed, 797 insertions(+), 7 deletions(-) create mode 100644 CLAUDE.md create mode 100644 apps/customer-service/src/auth/auth.service.spec.ts create mode 100644 apps/customer-service/src/clients/clients.service.spec.ts create mode 100644 apps/customer-service/src/visits/visits.service.spec.ts diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..de1d98b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,95 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +All commands run from repo root unless noted. Package manager: **pnpm**. + +```bash +# Dev (all apps in parallel) +pnpm dev + +# Build all +pnpm build + +# Lint / format +pnpm lint +pnpm lint:fix +pnpm format:fix + +# Typecheck +pnpm typecheck + +# Database +pnpm db:generate # regenerate Prisma client after schema change +pnpm db:push # push schema to DB (dev only, no migration file) +pnpm db:migrate:deploy # apply migrations (production-safe) +pnpm db:studio # Prisma Studio GUI + +# Run single app +pnpm --filter web dev +pnpm --filter customer-service dev + +# Run tests (customer-service only) +pnpm --filter customer-service test +pnpm --filter customer-service test:watch +pnpm --filter customer-service test:e2e +``` + +## Environment + +Copy `.env.example` to `.env` at repo root. All apps load it via `dotenv-cli` (`dotenv -e ../../.env`). + +Required vars: `DATABASE_URL`, `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `NEXT_PUBLIC_API_ENDPOINT`, `JWT_SECRET`. + +Start PostgreSQL: +```bash +docker compose up -d +``` +Port mapped: `5435:5432`. + +## Architecture + +**Turborepo monorepo** with pnpm workspaces. + +``` +apps/ + web/ # Next.js 16 frontend (port 3000) + customer-service/ # NestJS REST API (port 3001) +packages/ + database/ # Prisma schema + generated client (@notebook/postgres) + shared/ # Shared DTOs, enums, utils (@notebook/shared) + tsconfig/ # Shared TypeScript configs +``` + +### Frontend (`apps/web`) + +Next.js App Router with: +- **Auth**: client-side JWT stored in `localStorage` (`visit_notebook_access_token` / `visit_notebook_refresh_token`). `AuthContext` (`src/contexts/auth-context.tsx`) wraps the app; `(protected)/layout.tsx` redirects unauthenticated users. +- **Routing groups**: `(protected)` — authenticated pages (dashboard, clients, visits, statistics, profile); `(public)` — public pages; `login`, `register` — auth pages. +- **API client**: single file `src/lib/api.ts` — all HTTP calls go through here with automatic token injection and refresh logic. Base URL: `NEXT_PUBLIC_API_URL` env var (default `http://localhost:3001/api`). +- **i18n**: `next-intl` with cookie-based locale detection. Supported locales: `it` (default), `en`. Message files in `apps/web/messages/`. +- **UI**: Tailwind CSS v4 + Radix UI primitives + shadcn-style components in `src/components/ui/`. Recharts for statistics. + +### Backend (`apps/customer-service`) + +NestJS with: +- **Global guards**: `JwtAuthGuard` + `RolesGuard` applied to all routes by default. Use `@Public()` decorator to exempt a route. +- **Auth module**: JWT access tokens (15 min) + refresh tokens (httpOnly cookie). Strategies: `jwt` and `jwt-refresh`. Token hashing via `PasswordService`/`TokenService`. `AuditService` records user actions. +- **Domain modules**: `ClientsModule`, `VisitsModule` — each follows controller → service → Prisma pattern. +- **Exception handling**: `CustomApiException` + `ApiErrorCodes` in `src/exceptions/`. `ResponseHandler` for consistent response shapes. +- **Swagger**: available at `/swagger` in non-production environments. +- **Config**: loaded from `../../.env` via `ConfigModule.forRoot`. + +### Database (`packages/database`) + +Prisma schema at `packages/database/prisma/schema.prisma`. Prisma client generated to `node_modules/@prisma-postgres-db` (custom output path). Import as `@notebook/postgres`. + +**Key domain models**: `Organization` (tenant) → `User`, `Client`, `Visit`. Multi-tenancy via `organizationId` on every business entity. Soft deletes on `Client` and `Visit` (`isDeleted` flag). `Visit` has `VisitNote[]`, `Attachment[]`, `ChecklistResult[]`, `VisitReport[]`. + +After schema changes: run `pnpm db:generate` to regenerate the client, then rebuild dependent packages. + +### Shared (`packages/shared`) + +DTOs, enums, and utility classes (`SmartObject`, `SmartValue`, `SmartArray`) shared between frontend and backend. Import as `@notebook/shared`. diff --git a/apps/customer-service/src/auth/auth.service.spec.ts b/apps/customer-service/src/auth/auth.service.spec.ts new file mode 100644 index 0000000..2fd18c2 --- /dev/null +++ b/apps/customer-service/src/auth/auth.service.spec.ts @@ -0,0 +1,260 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ConflictException, UnauthorizedException } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { AuthService } from './auth.service'; +import { TokenService } from './services/token.service'; +import { PasswordService } from './services/password.service'; +import { AuditService } from './services/audit.service'; +import { prismaPostgres } from '@notebook/postgres'; + +const mockTransactionFn = jest.fn(); + +jest.mock('@notebook/postgres', () => ({ + prismaPostgres: { + user: { + findUnique: jest.fn(), + create: jest.fn(), + update: jest.fn(), + }, + organization: { + findUnique: jest.fn(), + create: jest.fn(), + }, + auditLog: { + create: jest.fn(), + }, + $transaction: (...args: any[]) => mockTransactionFn(...args), + }, + UserRole: { ADMIN: 'ADMIN', USER: 'USER' }, + AuditAction: { + USER_CREATED: 'USER_CREATED', + USER_LOGIN: 'USER_LOGIN', + USER_LOGOUT: 'USER_LOGOUT', + USER_UPDATED: 'USER_UPDATED', + }, +})); + +const db = prismaPostgres as jest.Mocked; + +const mockTokenService = { + generateTokens: jest.fn(), + verifyRefreshToken: jest.fn(), + revokeRefreshToken: jest.fn(), +}; + +const mockPasswordService = { + hashPassword: jest.fn(), + verifyPassword: jest.fn(), +}; + +const mockAuditService = { log: jest.fn() }; +const mockConfigService = { get: jest.fn() }; + +describe('AuthService', () => { + let service: AuthService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + AuthService, + { provide: TokenService, useValue: mockTokenService }, + { provide: PasswordService, useValue: mockPasswordService }, + { provide: AuditService, useValue: mockAuditService }, + { provide: ConfigService, useValue: mockConfigService }, + ], + }).compile(); + + service = module.get(AuthService); + jest.clearAllMocks(); + mockAuditService.log.mockResolvedValue(undefined); + (db.auditLog.create as jest.Mock).mockResolvedValue({}); + }); + + describe('register', () => { + it('throws ConflictException when email already exists', async () => { + (db.user.findUnique as jest.Mock).mockResolvedValue({ id: 'u1', email: 'test@example.com' }); + + await expect( + service.register({ + email: 'test@example.com', + password: 'pass', + organizationSlug: 'acme', + firstName: 'John', + lastName: 'Doe', + }), + ).rejects.toThrow(ConflictException); + }); + + it('creates user and org via transaction', async () => { + const newUser = { + id: 'u1', + email: 'new@example.com', + passwordHash: 'hash', + organization: { id: 'org-1' }, + }; + const tokens = { accessToken: 'at', refreshToken: 'rt' }; + + (db.user.findUnique as jest.Mock).mockResolvedValue(null); + mockPasswordService.hashPassword.mockResolvedValue('hashed'); + mockTransactionFn.mockImplementation(async (fn: any) => { + const tx = { + organization: { + findUnique: jest.fn().mockResolvedValue({ id: 'org-1', slug: 'acme' }), + create: jest.fn(), + }, + user: { create: jest.fn().mockResolvedValue(newUser) }, + }; + return fn(tx); + }); + mockTokenService.generateTokens.mockResolvedValue(tokens); + + const result = await service.register({ + email: 'new@example.com', + password: 'pass123', + organizationSlug: 'acme', + firstName: 'John', + lastName: 'Doe', + }); + + expect(result.accessToken).toBe('at'); + expect(result.user).toBeDefined(); + expect(result.user.passwordHash).toBeUndefined(); + }); + }); + + describe('login', () => { + it('throws UnauthorizedException when user not found', async () => { + (db.user.findUnique as jest.Mock).mockResolvedValue(null); + + await expect(service.login({ email: 'nobody@example.com', password: 'pass' })).rejects.toThrow( + UnauthorizedException, + ); + }); + + it('throws UnauthorizedException when user is inactive', async () => { + (db.user.findUnique as jest.Mock).mockResolvedValue({ + id: 'u1', + isActive: false, + organization: { isActive: true }, + }); + + await expect(service.login({ email: 'test@example.com', password: 'pass' })).rejects.toThrow( + UnauthorizedException, + ); + }); + + it('throws UnauthorizedException when organization is inactive', async () => { + (db.user.findUnique as jest.Mock).mockResolvedValue({ + id: 'u1', + isActive: true, + organization: { isActive: false }, + passwordHash: 'hash', + }); + + await expect(service.login({ email: 'test@example.com', password: 'pass' })).rejects.toThrow( + UnauthorizedException, + ); + }); + + it('throws UnauthorizedException when password is wrong', async () => { + (db.user.findUnique as jest.Mock).mockResolvedValue({ + id: 'u1', + isActive: true, + organization: { isActive: true }, + passwordHash: 'hash', + }); + mockPasswordService.verifyPassword.mockResolvedValue(false); + + await expect(service.login({ email: 'test@example.com', password: 'wrong' })).rejects.toThrow( + UnauthorizedException, + ); + }); + + it('returns tokens and user on success', async () => { + const user = { + id: 'u1', + email: 'test@example.com', + isActive: true, + organizationId: 'org-1', + passwordHash: 'hash', + organization: { id: 'org-1', isActive: true }, + }; + const tokens = { accessToken: 'at', refreshToken: 'rt' }; + + (db.user.findUnique as jest.Mock).mockResolvedValue(user); + mockPasswordService.verifyPassword.mockResolvedValue(true); + (db.user.update as jest.Mock).mockResolvedValue(user); + mockTokenService.generateTokens.mockResolvedValue(tokens); + + const result = await service.login({ email: 'test@example.com', password: 'correct' }); + + expect(result.accessToken).toBe('at'); + expect(result.user.passwordHash).toBeUndefined(); + }); + }); + + describe('refreshTokens', () => { + it('throws UnauthorizedException when user not found after token verify', async () => { + mockTokenService.verifyRefreshToken.mockResolvedValue({ sub: 'u1' }); + (db.user.findUnique as jest.Mock).mockResolvedValue(null); + + await expect(service.refreshTokens('rt')).rejects.toThrow(UnauthorizedException); + }); + + it('revokes old token and generates new ones', async () => { + const user = { + id: 'u1', + email: 'test@example.com', + isActive: true, + organizationId: 'org-1', + organization: { isActive: true }, + }; + const tokens = { accessToken: 'new-at', refreshToken: 'new-rt' }; + + mockTokenService.verifyRefreshToken.mockResolvedValue({ sub: 'u1' }); + (db.user.findUnique as jest.Mock).mockResolvedValue(user); + mockTokenService.revokeRefreshToken.mockResolvedValue(undefined); + mockTokenService.generateTokens.mockResolvedValue(tokens); + + const result = await service.refreshTokens('old-rt'); + + expect(mockTokenService.revokeRefreshToken).toHaveBeenCalledWith('old-rt'); + expect(result.accessToken).toBe('new-at'); + }); + }); + + describe('logout', () => { + it('revokes refresh token and logs audit', async () => { + mockTokenService.revokeRefreshToken.mockResolvedValue(undefined); + + await service.logout('rt', 'user-1'); + + expect(mockTokenService.revokeRefreshToken).toHaveBeenCalledWith('rt'); + expect(mockAuditService.log).toHaveBeenCalled(); + }); + }); + + describe('changePassword', () => { + it('throws UnauthorizedException when current password wrong', async () => { + (db.user.findUnique as jest.Mock).mockResolvedValue({ id: 'u1', passwordHash: 'hash' }); + mockPasswordService.verifyPassword.mockResolvedValue(false); + + await expect(service.changePassword('u1', 'wrong', 'new')).rejects.toThrow(UnauthorizedException); + }); + + it('updates password hash on success', async () => { + (db.user.findUnique as jest.Mock).mockResolvedValue({ id: 'u1', passwordHash: 'old-hash' }); + mockPasswordService.verifyPassword.mockResolvedValue(true); + mockPasswordService.hashPassword.mockResolvedValue('new-hash'); + (db.user.update as jest.Mock).mockResolvedValue({}); + + const result = await service.changePassword('u1', 'current', 'new-pass'); + + expect(db.user.update).toHaveBeenCalledWith({ + where: { id: 'u1' }, + data: { passwordHash: 'new-hash' }, + }); + expect(result.message).toBe('Password changed successfully'); + }); + }); +}); diff --git a/apps/customer-service/src/clients/clients.service.spec.ts b/apps/customer-service/src/clients/clients.service.spec.ts new file mode 100644 index 0000000..d3c7119 --- /dev/null +++ b/apps/customer-service/src/clients/clients.service.spec.ts @@ -0,0 +1,179 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { NotFoundException } from '@nestjs/common'; +import { ClientsService } from './clients.service'; +import { prismaPostgres } from '@notebook/postgres'; + +jest.mock('@notebook/postgres', () => ({ + prismaPostgres: { + client: { + create: jest.fn(), + findMany: jest.fn(), + findFirst: jest.fn(), + count: jest.fn(), + update: jest.fn(), + }, + visit: { + updateMany: jest.fn(), + }, + }, +})); + +const db = prismaPostgres as jest.Mocked; + +const mockUser = { + sub: 'user-1', + email: 'test@example.com', + role: 'ADMIN' as any, + organizationId: 'org-1', +}; + +describe('ClientsService', () => { + let service: ClientsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ClientsService], + }).compile(); + + service = module.get(ClientsService); + jest.clearAllMocks(); + }); + + describe('create', () => { + it('creates client scoped to organization', async () => { + const dto = { name: 'Acme Corp' }; + const expected = { id: 'client-1', name: 'Acme Corp', organizationId: 'org-1' }; + (db.client.create as jest.Mock).mockResolvedValue(expected); + + const result = await service.create(dto as any, mockUser); + + expect(db.client.create).toHaveBeenCalledWith({ + data: { ...dto, organizationId: 'org-1' }, + }); + expect(result).toEqual(expected); + }); + }); + + describe('findAll', () => { + it('returns paginated clients', async () => { + const clients = [{ id: 'c1', name: 'Client 1' }]; + (db.client.findMany as jest.Mock).mockResolvedValue(clients); + (db.client.count as jest.Mock).mockResolvedValue(1); + + const result = await service.findAll(mockUser, { page: 1, limit: 10 }); + + expect(result.data).toEqual(clients); + expect(result.meta).toEqual({ total: 1, page: 1, limit: 10, totalPages: 1 }); + }); + + it('applies search filter when provided', async () => { + (db.client.findMany as jest.Mock).mockResolvedValue([]); + (db.client.count as jest.Mock).mockResolvedValue(0); + + await service.findAll(mockUser, { page: 1, limit: 10, search: 'acme' }); + + const call = (db.client.findMany as jest.Mock).mock.calls[0][0]; + expect(call.where).toHaveProperty('OR'); + }); + + it('uses defaults when no options provided', async () => { + (db.client.findMany as jest.Mock).mockResolvedValue([]); + (db.client.count as jest.Mock).mockResolvedValue(0); + + const result = await service.findAll(mockUser); + + expect(result.meta.page).toBe(1); + expect(result.meta.limit).toBe(10); + }); + }); + + describe('findOne', () => { + it('returns client when found', async () => { + const client = { id: 'c1', name: 'Test' }; + (db.client.findFirst as jest.Mock).mockResolvedValue(client); + + const result = await service.findOne('c1', mockUser); + + expect(result).toEqual(client); + }); + + it('throws NotFoundException when client does not exist', async () => { + (db.client.findFirst as jest.Mock).mockResolvedValue(null); + + await expect(service.findOne('missing', mockUser)).rejects.toThrow(NotFoundException); + }); + }); + + describe('update', () => { + it('updates client when found', async () => { + const existing = { id: 'c1', name: 'Old Name' }; + const updated = { id: 'c1', name: 'New Name' }; + (db.client.findFirst as jest.Mock).mockResolvedValue(existing); + (db.client.update as jest.Mock).mockResolvedValue(updated); + + const result = await service.update('c1', { name: 'New Name' } as any, mockUser); + + expect(db.client.update).toHaveBeenCalledWith({ + where: { id: 'c1' }, + data: { name: 'New Name' }, + }); + expect(result).toEqual(updated); + }); + + it('throws NotFoundException when client not in organization', async () => { + (db.client.findFirst as jest.Mock).mockResolvedValue(null); + + await expect(service.update('missing', {} as any, mockUser)).rejects.toThrow(NotFoundException); + }); + }); + + describe('remove', () => { + it('soft deletes client and associated visits', async () => { + const existing = { id: 'c1', visits: [{ id: 'v1' }, { id: 'v2' }] }; + (db.client.findFirst as jest.Mock).mockResolvedValue(existing); + (db.client.update as jest.Mock).mockResolvedValue({ id: 'c1', isDeleted: true }); + (db.visit.updateMany as jest.Mock).mockResolvedValue({ count: 2 }); + + await service.remove('c1', mockUser); + + expect(db.visit.updateMany).toHaveBeenCalledWith({ + where: { clientId: 'c1', isDeleted: false }, + data: { isDeleted: true }, + }); + expect(db.client.update).toHaveBeenCalledWith({ + where: { id: 'c1' }, + data: { isDeleted: true }, + }); + }); + + it('skips visit deletion when no visits', async () => { + const existing = { id: 'c1', visits: [] }; + (db.client.findFirst as jest.Mock).mockResolvedValue(existing); + (db.client.update as jest.Mock).mockResolvedValue({ id: 'c1', isDeleted: true }); + + await service.remove('c1', mockUser); + + expect(db.visit.updateMany).not.toHaveBeenCalled(); + }); + + it('throws NotFoundException when client not found', async () => { + (db.client.findFirst as jest.Mock).mockResolvedValue(null); + + await expect(service.remove('missing', mockUser)).rejects.toThrow(NotFoundException); + }); + }); + + describe('search', () => { + it('returns matching clients', async () => { + const clients = [{ id: 'c1', name: 'Acme' }]; + (db.client.findMany as jest.Mock).mockResolvedValue(clients); + + const result = await service.search('Acme', mockUser); + + expect(result).toEqual(clients); + const call = (db.client.findMany as jest.Mock).mock.calls[0][0]; + expect(call.where.organizationId).toBe('org-1'); + expect(call.where).toHaveProperty('OR'); + }); + }); +}); diff --git a/apps/customer-service/src/visits/visits.service.spec.ts b/apps/customer-service/src/visits/visits.service.spec.ts new file mode 100644 index 0000000..8ada39c --- /dev/null +++ b/apps/customer-service/src/visits/visits.service.spec.ts @@ -0,0 +1,256 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { + NotFoundException, + ForbiddenException, + BadRequestException, +} from '@nestjs/common'; +import { VisitsService } from './visits.service'; +import { AuditService } from '../auth/services/audit.service'; +import { prismaPostgres } from '@notebook/postgres'; + +jest.mock('@notebook/postgres', () => ({ + prismaPostgres: { + visit: { + create: jest.fn(), + findMany: jest.fn(), + findFirst: jest.fn(), + update: jest.fn(), + count: jest.fn(), + }, + client: { + findFirst: jest.fn(), + }, + visitNote: { + create: jest.fn(), + findUnique: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + }, + auditLog: { + create: jest.fn(), + }, + }, + VisitStatus: { + DRAFT: 'DRAFT', + IN_PROGRESS: 'IN_PROGRESS', + COMPLETED: 'COMPLETED', + }, + AuditAction: { + VISIT_CREATED: 'VISIT_CREATED', + VISIT_UPDATED: 'VISIT_UPDATED', + VISIT_COMPLETED: 'VISIT_COMPLETED', + VISIT_DELETED: 'VISIT_DELETED', + }, +})); + +const db = prismaPostgres as jest.Mocked; + +const mockUser = { + sub: 'user-1', + email: 'test@example.com', + role: 'ADMIN' as any, + organizationId: 'org-1', +}; + +const mockAuditService = { log: jest.fn().mockResolvedValue(undefined) }; + +describe('VisitsService', () => { + let service: VisitsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + VisitsService, + { provide: AuditService, useValue: mockAuditService }, + ], + }).compile(); + + service = module.get(VisitsService); + jest.clearAllMocks(); + mockAuditService.log.mockResolvedValue(undefined); + (db.auditLog.create as jest.Mock).mockResolvedValue({}); + }); + + describe('create', () => { + it('throws NotFoundException when client does not belong to org', async () => { + (db.client.findFirst as jest.Mock).mockResolvedValue(null); + + await expect( + service.create( + { clientId: 'c1', scheduledAt: '2025-01-01', location: 'Milan' } as any, + mockUser, + ), + ).rejects.toThrow(NotFoundException); + }); + + it('creates visit as DRAFT', async () => { + const client = { id: 'c1', name: 'Acme' }; + const created = { id: 'v1', status: 'DRAFT', clientId: 'c1' }; + (db.client.findFirst as jest.Mock).mockResolvedValue(client); + (db.visit.create as jest.Mock).mockResolvedValue(created); + + const result = await service.create( + { clientId: 'c1', scheduledAt: '2025-01-01T10:00:00Z', location: 'Milan' } as any, + mockUser, + ); + + const call = (db.visit.create as jest.Mock).mock.calls[0][0]; + expect(call.data.status).toBe('DRAFT'); + expect(call.data.authorId).toBe('user-1'); + expect(call.data.organizationId).toBe('org-1'); + expect(result).toEqual(created); + }); + }); + + describe('findAll', () => { + it('returns paginated visits', async () => { + const visits = [{ id: 'v1' }]; + (db.visit.findMany as jest.Mock).mockResolvedValue(visits); + (db.visit.count as jest.Mock).mockResolvedValue(1); + + const result = await service.findAll({} as any, mockUser); + + expect(result.data).toEqual(visits); + expect(result.pagination.total).toBe(1); + }); + }); + + describe('findOne', () => { + it('throws NotFoundException when visit not found', async () => { + (db.visit.findFirst as jest.Mock).mockResolvedValue(null); + + await expect(service.findOne('missing', mockUser)).rejects.toThrow(NotFoundException); + }); + + it('returns visit when found', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'user-1' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + const result = await service.findOne('v1', mockUser); + + expect(result).toEqual(visit); + }); + }); + + describe('update', () => { + it('throws ForbiddenException when user is not author and not admin', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'other-user' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + const notAdmin = { ...mockUser, role: 'USER' as any }; + await expect(service.update('v1', {} as any, notAdmin)).rejects.toThrow(ForbiddenException); + }); + + it('throws BadRequestException when visit is completed and no status change', async () => { + const visit = { id: 'v1', status: 'COMPLETED', authorId: 'user-1' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + await expect(service.update('v1', { location: 'Rome' } as any, mockUser)).rejects.toThrow(BadRequestException); + }); + + it('updates visit when author', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'user-1' }; + const updated = { ...visit, location: 'Rome' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + (db.visit.update as jest.Mock).mockResolvedValue(updated); + + const result = await service.update('v1', { location: 'Rome' } as any, mockUser); + + expect(result).toEqual(updated); + }); + }); + + describe('complete', () => { + it('throws BadRequestException when already completed', async () => { + const visit = { id: 'v1', status: 'COMPLETED', authorId: 'user-1' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + await expect(service.complete('v1', mockUser)).rejects.toThrow(BadRequestException); + }); + + it('throws ForbiddenException when not owner', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'other-user' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + const notAdmin = { ...mockUser, role: 'USER' as any }; + await expect(service.complete('v1', notAdmin)).rejects.toThrow(ForbiddenException); + }); + + it('sets status to COMPLETED and completedAt', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'user-1' }; + const completed = { ...visit, status: 'COMPLETED', completedAt: new Date() }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + (db.visit.update as jest.Mock).mockResolvedValue(completed); + + const result = await service.complete('v1', mockUser); + + const call = (db.visit.update as jest.Mock).mock.calls[0][0]; + expect(call.data.status).toBe('COMPLETED'); + expect(call.data.completedAt).toBeInstanceOf(Date); + expect(result).toEqual(completed); + }); + }); + + describe('remove', () => { + it('throws ForbiddenException when not owner', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'other-user' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + const notAdmin = { ...mockUser, role: 'USER' as any }; + await expect(service.remove('v1', notAdmin)).rejects.toThrow(ForbiddenException); + }); + + it('throws BadRequestException when visit is completed', async () => { + const visit = { id: 'v1', status: 'COMPLETED', authorId: 'user-1' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + await expect(service.remove('v1', mockUser)).rejects.toThrow(BadRequestException); + }); + + it('soft deletes draft visit', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'user-1' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + (db.visit.update as jest.Mock).mockResolvedValue({ ...visit, isDeleted: true }); + + const result = await service.remove('v1', mockUser); + + expect(db.visit.update).toHaveBeenCalledWith({ + where: { id: 'v1' }, + data: { isDeleted: true }, + }); + expect(result).toEqual({ message: 'Visit deleted successfully' }); + }); + }); + + describe('addNote', () => { + it('throws ForbiddenException when not visit owner', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'other-user' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + const notAdmin = { ...mockUser, role: 'USER' as any }; + await expect( + service.addNote({ visitId: 'v1', content: 'note' } as any, notAdmin), + ).rejects.toThrow(ForbiddenException); + }); + + it('throws BadRequestException when visit is completed', async () => { + const visit = { id: 'v1', status: 'COMPLETED', authorId: 'user-1' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + + await expect( + service.addNote({ visitId: 'v1', content: 'note' } as any, mockUser), + ).rejects.toThrow(BadRequestException); + }); + + it('creates note when allowed', async () => { + const visit = { id: 'v1', status: 'DRAFT', authorId: 'user-1' }; + const note = { id: 'n1', content: 'test note', visitId: 'v1' }; + (db.visit.findFirst as jest.Mock).mockResolvedValue(visit); + (db.visitNote.create as jest.Mock).mockResolvedValue(note); + + const result = await service.addNote({ visitId: 'v1', content: 'test note' } as any, mockUser); + + expect(result).toEqual(note); + }); + }); +}); diff --git a/apps/customer-service/tsconfig.json b/apps/customer-service/tsconfig.json index f6835d3..39e780f 100644 --- a/apps/customer-service/tsconfig.json +++ b/apps/customer-service/tsconfig.json @@ -9,7 +9,6 @@ "target": "ES2021", "sourceMap": true, "outDir": "./dist", - "baseUrl": "./", "incremental": true, "skipLibCheck": true, "strictNullChecks": false, @@ -17,6 +16,7 @@ "strictBindCallApply": false, "forceConsistentCasingInFileNames": false, "noFallthroughCasesInSwitch": false, - "jsx": "preserve" + "jsx": "preserve", + "types": ["jest"] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1579eb..5cf8afd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8531,7 +8531,7 @@ snapshots: '@next/eslint-plugin-next': 16.2.6 eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) @@ -8558,7 +8558,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -8573,14 +8573,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color @@ -8595,7 +8595,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 From 8ab7365765d08a873e5817d2f2e06ed84272d987 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Thu, 4 Jun 2026 22:35:47 +0200 Subject: [PATCH 07/13] add web and api dockefiles and update ci --- .docker/Dockerfile.customer | 56 +++++++++++++++ .docker/Dockerfile.web | 61 +++++++++++++++++ .github/workflows/ci.yml | 2 +- .github/workflows/docker.yml | 129 +++++++++++++++++++++++++++++++++++ .nvmrc | 2 +- apps/web/next.config.ts | 1 + package.json | 2 +- 7 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 .docker/Dockerfile.customer create mode 100644 .docker/Dockerfile.web create mode 100644 .github/workflows/docker.yml diff --git a/.docker/Dockerfile.customer b/.docker/Dockerfile.customer new file mode 100644 index 0000000..4269f57 --- /dev/null +++ b/.docker/Dockerfile.customer @@ -0,0 +1,56 @@ +# ───────────────────────────────────────────────────────────────────────────── +# MULTI-STAGE BUILD con turbo prune +# +# Stage 1 (pruner): turbo prune isola SOLO i file di customer-service +# → out/json/ = package.json dei package necessari +# → out/full/ = sorgente completo (app + deps locali) +# → out/pnpm-lock.yaml = lockfile potato +# +# Stage 2 (deps): copia solo out/json/ + lockfile, installa dipendenze +# → layer Docker stabile: si ricostruisce solo se lockfile cambia +# +# Stage 3 (builder): copia sorgente, compila TypeScript +# +# Stage 4 (runner): immagine finale minimale — solo dist/ + node_modules +# niente devDependencies, niente sorgente TypeScript +# ───────────────────────────────────────────────────────────────────────────── + +FROM node:24-alpine AS base +RUN npm install -g pnpm@11.5.1 +WORKDIR /app + +# ── Stage 1: prune ──────────────────────────────────────────────────────────── +# Unico stage che vede tutta la codebase. turbo prune la taglia. +FROM base AS pruner +RUN npm install -g turbo +COPY . . +RUN turbo prune --scope=customer-service --docker + +# ── Stage 2: deps ───────────────────────────────────────────────────────────── +# Solo package.json + lockfile → layer cachato separato dal sorgente. +# Se cambia solo il codice (non le dipendenze), questo layer non si ricostruisce. +FROM base AS deps +COPY --from=pruner /app/out/json/ . +COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +RUN pnpm install --frozen-lockfile + +# ── Stage 3: builder ────────────────────────────────────────────────────────── +FROM base AS builder +COPY --from=deps /app/node_modules ./node_modules +COPY --from=pruner /app/out/full/ . +RUN pnpm --filter customer-service build + +# ── Stage 4: runner ─────────────────────────────────────────────────────────── +# Immagine production: solo runtime, no devDeps, no sorgente TypeScript. +FROM node:24-alpine AS runner +WORKDIR /app + +# Utente non-root per sicurezza +RUN addgroup -S appgroup && adduser -S appuser -G appgroup + +COPY --from=builder /app/apps/customer-service/dist ./dist +COPY --from=builder /app/node_modules ./node_modules + +USER appuser +EXPOSE 3001 +CMD ["node", "dist/main"] diff --git a/.docker/Dockerfile.web b/.docker/Dockerfile.web new file mode 100644 index 0000000..087e6d7 --- /dev/null +++ b/.docker/Dockerfile.web @@ -0,0 +1,61 @@ +# ───────────────────────────────────────────────────────────────────────────── +# MULTI-STAGE BUILD per Next.js standalone +# +# Stage 1 (pruner): turbo prune isola solo i file di web + sue dipendenze locali +# +# Stage 2 (deps): installa dipendenze dal lockfile potato +# +# Stage 3 (builder): compila Next.js in modalità standalone +# output in apps/web/.next/standalone/ — server.js auto-contenuto +# +# Stage 4 (runner): immagine finale minimale +# .next/standalone → server runtime +# .next/static → asset statici (JS/CSS bundles) +# public/ → file pubblici (favicon, immagini) +# +# NOTA: standalone non include .next/static e public/ — vanno copiati separatamente. +# In production si usa nginx davanti per servire gli static e fare reverse proxy. +# ───────────────────────────────────────────────────────────────────────────── + +FROM node:24-alpine AS base +RUN npm install -g pnpm@11.5.1 +WORKDIR /app + +# ── Stage 1: prune ──────────────────────────────────────────────────────────── +FROM base AS pruner +RUN npm install -g turbo +COPY . . +RUN turbo prune --scope=web --docker + +# ── Stage 2: deps ───────────────────────────────────────────────────────────── +FROM base AS deps +COPY --from=pruner /app/out/json/ . +COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +RUN pnpm install --frozen-lockfile + +# ── Stage 3: builder ────────────────────────────────────────────────────────── +FROM base AS builder +COPY --from=deps /app/node_modules ./node_modules +COPY --from=pruner /app/out/full/ . +ENV NEXT_TELEMETRY_DISABLED=1 +RUN pnpm --filter web build + +# ── Stage 4: runner ─────────────────────────────────────────────────────────── +FROM node:24-alpine AS runner +WORKDIR /app + +RUN addgroup -S appgroup && adduser -S appuser -G appgroup + +# standalone contiene server.js + node_modules minimale (solo runtime deps) +COPY --from=builder /app/apps/web/.next/standalone ./ +# static assets e public vanno copiati separatamente (non inclusi in standalone) +COPY --from=builder /app/apps/web/.next/static ./apps/web/.next/static +COPY --from=builder /app/apps/web/public ./apps/web/public + +USER appuser +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 +ENV NEXT_TELEMETRY_DISABLED=1 +# server.js generato da Next.js standalone si trova nella root dello standalone +CMD ["node", "apps/web/server.js"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ea7e3b..67c838b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ env: NODE_ENV: test NEXT_TELEMETRY_DISABLED: "1" TURBO_TELEMETRY_DISABLED: "1" - PNPM_VERSION: "9.14.4" + PNPM_VERSION: "11.5.1" NODE_VERSION: "22" # ───────────────────────────────────────────────────────────────────────────── diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..fa31078 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,129 @@ +# ───────────────────────────────────────────────────────────────────────────── +# DOCKER — build e push immagini su GitHub Container Registry (GHCR) +# +# GHCR è il registry Docker integrato in GitHub, gratuito per repo pubblici. +# Le immagini sono accessibili su: ghcr.io/// +# +# PERCHÉ NON docker compose build? +# - docker compose non supporta BuildKit cache per-layer su GHA +# - meno controllo sui tag (sha, branch, latest) +# - docker/build-push-action è lo standard GHA: BuildKit nativo, cache GHA +# +# CACHE STRATEGIA (type=gha): +# - GHA salva i layer Docker tra una run e l'altra +# - Se cambiano solo i sorgenti (non le dipendenze), lo stage "deps" è cached +# - Prima run: ~5 min. Run successive con solo code changes: ~2 min. +# +# TAG STRATEGIA: +# - sha- → tag immutabile per ogni commit (es. sha-abc1234) +# - main → tag mobile che punta all'ultimo commit su main +# - develop → idem per develop +# ───────────────────────────────────────────────────────────────────────────── + +name: Docker + +on: + push: + branches: + - main + - develop + - feature/** + # Triggera solo se cambiano file rilevanti per Docker. + # Evita build inutili per modifiche a docs, test, ecc. + paths: + - "apps/**" + - "packages/**" + - ".docker/**" + - "pnpm-lock.yaml" + - "turbo.json" + +# ───────────────────────────────────────────────────────────────────────────── +# CONCURRENCY +# Se arrivano due push in rapida successione sullo stesso branch, +# cancella la run precedente e parte con quella nuova. +# Evita di sprecare minuti runner su build già superate. +# ───────────────────────────────────────────────────────────────────────────── +concurrency: + group: docker-${{ github.ref }} + cancel-in-progress: true + +env: + REGISTRY: ghcr.io + +jobs: + # ─────────────────────────────────────────────────────────────────────────── + # MATRIX BUILD + # Un solo job con strategy.matrix costruisce entrambe le immagini IN PARALLELO. + # Aggiungere una terza app = aggiungere una riga alla matrix, nient'altro. + # + # matrix.include permette di specificare parametri diversi per ogni app: + # - app: nome usato nei log e nei tag + # - dockerfile: path del Dockerfile + # ─────────────────────────────────────────────────────────────────────────── + build-and-push: + name: Build ${{ matrix.app }} + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write # necessario per pushare su GHCR + + strategy: + matrix: + include: + - app: customer-service + dockerfile: .docker/Dockerfile.customer + - app: web + dockerfile: .docker/Dockerfile.web + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # ── docker/setup-buildx-action ────────────────────────────────────────── + # Abilita BuildKit — il builder moderno di Docker. + # Necessario per: multi-stage build paralleli, cache GHA, build cross-platform. + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # ── docker/login-action ───────────────────────────────────────────────── + # GITHUB_TOKEN è automatico — nessun secret da configurare manualmente. + # Permette di pushare su ghcr.io//. + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # ── docker/metadata-action ────────────────────────────────────────────── + # Genera i tag automaticamente in base al contesto Git. + # Output: steps.meta.outputs.tags → tutti i tag (stringa multi-riga) + # steps.meta.outputs.labels → OCI labels standard per l'immagine + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.app }} + tags: | + type=sha,prefix=sha-,format=short + type=ref,event=branch + + # ── docker/build-push-action ──────────────────────────────────────────── + # Build + push con BuildKit. + # + # cache-from: tenta di riutilizzare i layer dalla cache GHA + # cache-to: salva i layer nella cache GHA dopo il build + # mode=max: salva tutti i layer intermedi (anche degli stage non finali) + # → lo stage "deps" è cached anche se cambia solo il sorgente + # scope: isola la cache per app (evita collisioni tra customer e web) + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ${{ matrix.dockerfile }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=${{ matrix.app }} + cache-to: type=gha,mode=max,scope=${{ matrix.app }} diff --git a/.nvmrc b/.nvmrc index 410b14d..cabf43b 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -25 \ No newline at end of file +24 \ No newline at end of file diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index ab9f7a8..86ca40f 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -5,6 +5,7 @@ const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts"); const nextConfig: NextConfig = { /* config options here */ + output: 'standalone' }; export default withNextIntl(nextConfig); diff --git a/package.json b/package.json index d36338b..f474645 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "notebook", "version": "1.0.0", - "packageManager": "pnpm@9.14.4", + "packageManager": "pnpm@11.5.1", "type": "module", "engines": { "node": ">=18.18.0" From 0b025d42ef6c3bc62eace01875e66043efc7bfe7 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 5 Jun 2026 00:20:12 +0200 Subject: [PATCH 08/13] add docker compose and deploy workflow --- .docker/docker-compose.production.yml | 110 ++ .github/workflows/ci.yml | 2 +- .github/workflows/deploy.yml | 105 ++ .github/workflows/docker.yml | 2 +- apps/customer-service/package.json | 14 +- .../src/auth/services/audit.service.ts | 7 +- apps/customer-service/src/main.ts | 2 +- apps/customer-service/tsconfig.build.json | 4 + apps/web/package.json | 14 +- package.json | 10 +- packages/database/package.json | 4 +- packages/database/tsconfig.json | 1 + packages/shared/package.json | 4 +- packages/shared/tsconfig.json | 1 + packages/tsconfig/nestjs.json | 1 + pnpm-lock.yaml | 1399 +++++++++-------- pnpm-workspace.yaml | 12 + 17 files changed, 1001 insertions(+), 691 deletions(-) create mode 100644 .docker/docker-compose.production.yml create mode 100644 .github/workflows/deploy.yml diff --git a/.docker/docker-compose.production.yml b/.docker/docker-compose.production.yml new file mode 100644 index 0000000..a16dac8 --- /dev/null +++ b/.docker/docker-compose.production.yml @@ -0,0 +1,110 @@ +# ───────────────────────────────────────────────────────────────────────────── +# DOCKER COMPOSE — template per server di produzione/staging +# +# COME USARE: +# 1. Copia questo file sul server come ~/visit-notebook/docker-compose.yml +# 2. Crea ~/visit-notebook/.env con le variabili reali (non committare mai .env) +# 3. Crea ~/visit-notebook/nginx.conf (vedi sotto per un template base) +# 4. Sostituisci con il tuo GitHub username +# +# AGGIORNARE LE IMMAGINI: +# docker compose pull && docker compose up -d --remove-orphans +# (questo è esattamente quello che fa deploy.yml via SSH) +# ───────────────────────────────────────────────────────────────────────────── + +services: + + postgres: + image: postgres:16-alpine + restart: unless-stopped + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] + interval: 10s + timeout: 5s + retries: 5 + + customer-service: + image: ghcr.io//customer-service:main + restart: unless-stopped + environment: + NODE_ENV: production + DATABASE_URL: ${DATABASE_URL} + JWT_SECRET: ${JWT_SECRET} + NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL} + depends_on: + postgres: + condition: service_healthy + expose: + - "3001" + + web: + image: ghcr.io//web:main + restart: unless-stopped + environment: + NODE_ENV: production + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL} + expose: + - "3000" + + # ───────────────────────────────────────────────────────────────────────── + # NGINX — reverse proxy + # Espone solo le porte 80/443 all'esterno. + # web e customer-service non hanno porte host: accessibili solo via nginx. + # ───────────────────────────────────────────────────────────────────────── + nginx: + image: nginx:alpine + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + - ./certs:/etc/nginx/certs:ro # certificati TLS (es. Let's Encrypt) + depends_on: + - web + - customer-service + +volumes: + postgres_data: + +# ───────────────────────────────────────────────────────────────────────────── +# TEMPLATE .env (crea sul server, non nel repo) +# ───────────────────────────────────────────────────────────────────────────── +# POSTGRES_DB=notebook_prod +# POSTGRES_USER=notebook +# POSTGRES_PASSWORD= +# DATABASE_URL=postgresql://notebook:@postgres:5432/notebook_prod +# JWT_SECRET= +# NEXT_PUBLIC_API_URL=https://api.tuodominio.com/api +# NEXT_PUBLIC_APP_URL=https://tuodominio.com +# +# ───────────────────────────────────────────────────────────────────────────── +# TEMPLATE nginx.conf (base, senza TLS — aggiungi certbot/Let's Encrypt dopo) +# ───────────────────────────────────────────────────────────────────────────── +# events {} +# http { +# server { +# listen 80; +# server_name tuodominio.com; +# location / { +# proxy_pass http://web:3000; +# proxy_set_header Host $host; +# proxy_set_header X-Real-IP $remote_addr; +# } +# } +# server { +# listen 80; +# server_name api.tuodominio.com; +# location / { +# proxy_pass http://customer-service:3001; +# proxy_set_header Host $host; +# proxy_set_header X-Real-IP $remote_addr; +# } +# } +# } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67c838b..4f3e3de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ env: NEXT_TELEMETRY_DISABLED: "1" TURBO_TELEMETRY_DISABLED: "1" PNPM_VERSION: "11.5.1" - NODE_VERSION: "22" + NODE_VERSION: "24" # ───────────────────────────────────────────────────────────────────────────── # PERCHÉ NON PASSIAMO node_modules COME ARTIFACT? diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..e125bd3 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,105 @@ +# ───────────────────────────────────────────────────────────────────────────── +# DEPLOY — SSH deploy su server self-hosted dopo build Docker +# +# TRIGGER: workflow_run +# Parte quando "Prepare Docker images" completa con successo su main/develop. +# Garantisce che le immagini GHCR siano disponibili prima di deployare. +# +# DUE AMBIENTI: +# staging → develop → deploy automatico +# production → main → deploy con manual approval gate +# +# SECRETS (configurare in GitHub Settings → Environments): +# SSH_HOST IP o hostname del server +# SSH_USER utente SSH (es. ubuntu, deploy) +# SSH_PRIVATE_KEY chiave privata ED25519 +# GHCR_USER GitHub username (per docker login sul server) +# GHCR_TOKEN Personal Access Token con scope read:packages +# +# PREREQUISITI SUL SERVER: +# - Docker + Docker Compose installati +# - ~/visit-notebook/docker-compose.yml configurato con le immagini GHCR +# - ~/visit-notebook/.env con le variabili d'ambiente di produzione +# ───────────────────────────────────────────────────────────────────────────── + +name: Deploy + +on: + workflow_run: + workflows: ["Prepare Docker images"] + types: [completed] + branches: [main, develop] + +# ───────────────────────────────────────────────────────────────────────────── +# CONCURRENCY +# cancel-in-progress: false — non cancellare mai un deploy già in corso. +# Un deploy a metà strada lascerebbe il server in stato inconsistente. +# ───────────────────────────────────────────────────────────────────────────── +concurrency: + group: deploy-${{ github.event.workflow_run.head_branch }} + cancel-in-progress: false + +jobs: + + # ─────────────────────────────────────────────────────────────────────────── + # STAGING — develop → auto deploy + # ─────────────────────────────────────────────────────────────────────────── + deploy-staging: + name: Deploy → Staging + if: >- + github.event.workflow_run.conclusion == 'success' && + (github.event.workflow_run.head_branch == 'develop' || + github.event.workflow_run.head_branch == 'feature/cicd') + runs-on: ubuntu-latest + environment: staging + + permissions: + contents: read + packages: read + + steps: + - name: Deploy to staging via SSH + uses: appleboy/ssh-action@v1 + with: + host: ${{ secrets.SSH_HOST }} + username: ${{ secrets.SSH_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + cd ~/visit-notebook + docker compose pull + docker compose up -d --remove-orphans + docker image prune -f + + # ─────────────────────────────────────────────────────────────────────────── + # PRODUCTION — main → deploy con manual approval + # + # Il gate di approvazione manuale è configurato in GitHub: + # Settings → Environments → production → Required reviewers + # + # Il job si ferma qui finché qualcuno non approva dal pannello Actions. + # Pattern standard nelle aziende: nessuno deploya in prod senza review. + # ─────────────────────────────────────────────────────────────────────────── + deploy-production: + name: Deploy → Production + if: >- + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.head_branch == 'main' + runs-on: ubuntu-latest + environment: production + + permissions: + contents: read + packages: read + + steps: + - name: Deploy to production via SSH + uses: appleboy/ssh-action@v1 + with: + host: ${{ secrets.SSH_HOST }} + username: ${{ secrets.SSH_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + cd ~/visit-notebook + docker compose pull + docker compose up -d --remove-orphans + docker image prune -f diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index fa31078..1f968eb 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -20,7 +20,7 @@ # - develop → idem per develop # ───────────────────────────────────────────────────────────────────────────── -name: Docker +name: Prepare Docker images on: push: diff --git a/apps/customer-service/package.json b/apps/customer-service/package.json index beb646e..ba6b22e 100644 --- a/apps/customer-service/package.json +++ b/apps/customer-service/package.json @@ -21,7 +21,7 @@ "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config ./test/jest-e2e.json", + "test:e2e": "pnpm with-env jest --config ./test/jest-e2e.json", "with-env": "dotenv -e ../../.env --" }, "dependencies": { @@ -36,9 +36,9 @@ "@notebook/postgres": "workspace:^", "bcrypt": "^6.0.0", "class-transformer": "^0.5.1", - "class-validator": "^0.14.4", + "class-validator": "^0.15.1", "cookie-parser": "^1.4.7", - "date-fns": "^4.3.0", + "date-fns": "^4.4.0", "dotenv-cli": "^11.0.0", "passport": "^0.7.0", "passport-jwt": "^4.0.1", @@ -55,8 +55,8 @@ "@types/jest": "^30.0.0", "@types/node": "^25.9.1", "@types/passport-jwt": "^4.0.1", - "@types/supertest": "^6.0.3", - "eslint": "^9.39.4", + "@types/supertest": "^7.2.0", + "eslint": "^10.4.1", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.6", "jest": "^30.4.2", @@ -64,10 +64,10 @@ "source-map-support": "^0.5.21", "supertest": "^7.2.2", "ts-jest": "^29.4.11", - "ts-loader": "^9.5.7", + "ts-loader": "^9.6.0", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "^5.9.3" + "typescript": "^6.0.3" }, "jest": { "moduleFileExtensions": [ diff --git a/apps/customer-service/src/auth/services/audit.service.ts b/apps/customer-service/src/auth/services/audit.service.ts index 246543e..31663b5 100644 --- a/apps/customer-service/src/auth/services/audit.service.ts +++ b/apps/customer-service/src/auth/services/audit.service.ts @@ -40,11 +40,8 @@ export class AuditService { (entry.entityType ? ` on ${entry.entityType}:${entry.entityId}` : ''), ); } catch (error) { - // Audit logging should not break the main flow - this.logger.error( - `Failed to log audit event: ${error.message}`, - error.stack, - ); + const err = error instanceof Error ? error : new Error(String(error)); + this.logger.error(`Failed to log audit event: ${err.message}`, err.stack); } } diff --git a/apps/customer-service/src/main.ts b/apps/customer-service/src/main.ts index edb3f9a..97810ab 100644 --- a/apps/customer-service/src/main.ts +++ b/apps/customer-service/src/main.ts @@ -1,7 +1,7 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import * as process from 'process'; -import * as cookieParser from 'cookie-parser'; +import cookieParser from 'cookie-parser'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { Logger, ValidationPipe } from '@nestjs/common'; diff --git a/apps/customer-service/tsconfig.build.json b/apps/customer-service/tsconfig.build.json index 64f86c6..b4ea44f 100644 --- a/apps/customer-service/tsconfig.build.json +++ b/apps/customer-service/tsconfig.build.json @@ -1,4 +1,8 @@ { "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "tsBuildInfoFile": "./dist/.tsbuildinfo" + }, "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] } diff --git a/apps/web/package.json b/apps/web/package.json index 2e823be..2a743dd 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -27,16 +27,16 @@ "@radix-ui/react-toast": "^1.2.15", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "date-fns": "^4.3.0", + "date-fns": "^4.4.0", "framer-motion": "^12.40.0", - "lucide-react": "^0.563.0", + "lucide-react": "^1.17.0", "next": "16.2.6", "next-intl": "^4.13.0", "next-themes": "^0.4.6", "react": "19.2.6", - "react-day-picker": "^9.14.0", + "react-day-picker": "^10.0.1", "react-dom": "19.2.6", - "react-hook-form": "^7.76.1", + "react-hook-form": "^7.77.0", "recharts": "^3.8.1", "tailwind-merge": "^3.6.0", "zod": "^4.4.3" @@ -45,11 +45,11 @@ "@eslint/eslintrc": "3.3.3", "@tailwindcss/postcss": "^4.3.0", "@types/node": "^25.9.1", - "@types/react": "^19.2.15", + "@types/react": "^19.2.16", "@types/react-dom": "^19.2.3", - "eslint": "^9.39.4", + "eslint": "^10.4.1", "eslint-config-next": "16.2.6", "tailwindcss": "^4.3.0", - "typescript": "^5.9.3" + "typescript": "^6.0.3" } } diff --git a/package.json b/package.json index f474645..cceddda 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "packageManager": "pnpm@11.5.1", "type": "module", "engines": { - "node": ">=18.18.0" + "node": ">=24.0.0" }, "private": true, "scripts": { @@ -23,14 +23,14 @@ "db:studio": "turbo db:studio" }, "devDependencies": { - "@eslint/js": "^9.39.4", - "@next/eslint-plugin-next": "^16.2.6", - "eslint": "^9.39.4", + "@eslint/js": "^10.0.1", + "@next/eslint-plugin-next": "^16.2.7", + "eslint": "^10.4.1", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.1.1", "prettier": "^3.8.3", "tsconfig": "workspace:*", "turbo": "^2.9.16", - "typescript-eslint": "^8.60.0" + "typescript-eslint": "^8.60.1" } } diff --git a/packages/database/package.json b/packages/database/package.json index 5bba22e..fc49a10 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -23,10 +23,10 @@ }, "devDependencies": { "dotenv-cli": "^11.0.0", - "eslint": "^9.39.4", + "eslint": "^10.4.1", "prisma": "^6.19.3", "tsconfig": "workspace:*", - "typescript": "^5.9.3" + "typescript": "^6.0.3" }, "dependencies": { "@prisma/client": "^6.19.3" diff --git a/packages/database/tsconfig.json b/packages/database/tsconfig.json index 6cfc764..bb97a84 100644 --- a/packages/database/tsconfig.json +++ b/packages/database/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "outDir": "./dist", "baseUrl": "./", + "ignoreDeprecations": "6.0", "esModuleInterop": true }, "include": ["."], diff --git a/packages/shared/package.json b/packages/shared/package.json index 0be1a23..41c9944 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -13,8 +13,8 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { - "eslint": "^9.39.4", + "eslint": "^10.4.1", "prettier": "^3.8.3", - "typescript": "^5.9.3" + "typescript": "^6.0.3" } } diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index 754e2cc..00a44b4 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -11,6 +11,7 @@ "sourceMap": true, "outDir": "./dist", "baseUrl": "./", + "ignoreDeprecations": "6.0", "incremental": true, "skipLibCheck": true, "noImplicitAny": false, diff --git a/packages/tsconfig/nestjs.json b/packages/tsconfig/nestjs.json index 3d77a57..dda4fea 100644 --- a/packages/tsconfig/nestjs.json +++ b/packages/tsconfig/nestjs.json @@ -11,6 +11,7 @@ "sourceMap": true, "outDir": "./dist", "baseUrl": "./", + "ignoreDeprecations": "6.0", "incremental": true, "skipLibCheck": true, "strictNullChecks": false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5cf8afd..774c883 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,20 +9,20 @@ importers: .: devDependencies: '@eslint/js': - specifier: ^9.39.4 - version: 9.39.4 + specifier: ^10.0.1 + version: 10.0.1(eslint@10.4.1(jiti@2.7.0)) '@next/eslint-plugin-next': - specifier: ^16.2.6 - version: 16.2.6 + specifier: ^16.2.7 + version: 16.2.7 eslint: - specifier: ^9.39.4 - version: 9.39.4(jiti@2.7.0) + specifier: ^10.4.1 + version: 10.4.1(jiti@2.7.0) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@9.39.4(jiti@2.7.0)) + version: 7.37.5(eslint@10.4.1(jiti@2.7.0)) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + version: 7.1.1(eslint@10.4.1(jiti@2.7.0)) prettier: specifier: ^3.8.3 version: 3.8.3 @@ -33,35 +33,35 @@ importers: specifier: ^2.9.16 version: 2.9.16 typescript-eslint: - specifier: ^8.60.0 - version: 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + specifier: ^8.60.1 + version: 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) apps/customer-service: dependencies: '@nestjs/common': specifier: ^11.1.24 - version: 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': specifier: ^4.0.4 - version: 4.0.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 4.0.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': specifier: ^11.1.24 - version: 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/jwt': specifier: ^11.0.2 - version: 11.0.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + version: 11.0.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/mapped-types': specifier: ^2.1.1 - version: 2.1.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + version: 2.1.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) '@nestjs/passport': specifier: ^11.0.5 - version: 11.0.5(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) + version: 11.0.5(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) '@nestjs/platform-express': specifier: ^11.1.24 - version: 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) + version: 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) '@nestjs/swagger': specifier: ^11.4.4 - version: 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + version: 11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) '@notebook/postgres': specifier: workspace:^ version: link:../../packages/database @@ -72,14 +72,14 @@ importers: specifier: ^0.5.1 version: 0.5.1 class-validator: - specifier: ^0.14.4 - version: 0.14.4 + specifier: ^0.15.1 + version: 0.15.1 cookie-parser: specifier: ^1.4.7 version: 1.4.7 date-fns: - specifier: ^4.3.0 - version: 4.3.0 + specifier: ^4.4.0 + version: 4.4.0 dotenv-cli: specifier: ^11.0.0 version: 11.0.0 @@ -101,10 +101,10 @@ importers: version: 11.0.21(@swc/core@1.15.40)(@types/node@25.9.1)(prettier@3.8.3) '@nestjs/schematics': specifier: ^11.1.0 - version: 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) + version: 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@6.0.3) '@nestjs/testing': specifier: ^11.1.24 - version: 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/platform-express@11.1.24) + version: 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/platform-express@11.1.24) '@types/bcrypt': specifier: ^6.0.0 version: 6.0.0 @@ -124,20 +124,20 @@ importers: specifier: ^4.0.1 version: 4.0.1 '@types/supertest': - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.2.0 + version: 7.2.0 eslint: - specifier: ^9.39.4 - version: 9.39.4(jiti@2.7.0) + specifier: ^10.4.1 + version: 10.4.1(jiti@2.7.0) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.4(jiti@2.7.0)) + version: 10.1.8(eslint@10.4.1(jiti@2.7.0)) eslint-plugin-prettier: specifier: ^5.5.6 - version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.3) + version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0))(prettier@3.8.3) jest: specifier: ^30.4.2 - version: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)) + version: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)) prettier: specifier: ^3.8.3 version: 3.8.3 @@ -149,58 +149,58 @@ importers: version: 7.2.2 ts-jest: specifier: ^29.4.11 - version: 29.4.11(@babel/core@7.29.7)(@jest/transform@30.4.1)(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7))(jest-util@30.4.1)(jest@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.7)(@jest/transform@30.4.1)(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7))(jest-util@30.4.1)(jest@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)))(typescript@6.0.3) ts-loader: - specifier: ^9.5.7 - version: 9.5.7(typescript@5.9.3)(webpack@5.106.0(@swc/core@1.15.40)) + specifier: ^9.6.0 + version: 9.6.0(typescript@6.0.3)(webpack@5.106.0(@swc/core@1.15.40)) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3) + version: 10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3) tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 apps/web: dependencies: '@hookform/resolvers': specifier: ^5.4.0 - version: 5.4.0(react-hook-form@7.76.1(react@19.2.6)) + version: 5.4.0(react-hook-form@7.77.0(react@19.2.6)) '@radix-ui/react-avatar': specifier: ^1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-dialog': specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 - version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-label': specifier: ^2.1.8 - version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-popover': specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-select': specifier: ^2.2.6 - version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-separator': specifier: ^1.1.8 - version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-slot': specifier: ^1.2.4 - version: 1.2.4(@types/react@19.2.15)(react@19.2.6) + version: 1.2.4(@types/react@19.2.16)(react@19.2.6) '@radix-ui/react-switch': specifier: ^1.2.6 - version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-tabs': specifier: ^1.1.13 - version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-toast': specifier: ^1.2.15 - version: 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -208,20 +208,20 @@ importers: specifier: ^2.1.1 version: 2.1.1 date-fns: - specifier: ^4.3.0 - version: 4.3.0 + specifier: ^4.4.0 + version: 4.4.0 framer-motion: specifier: ^12.40.0 version: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) lucide-react: - specifier: ^0.563.0 - version: 0.563.0(react@19.2.6) + specifier: ^1.17.0 + version: 1.17.0(react@19.2.6) next: specifier: 16.2.6 version: 16.2.6(@babel/core@7.29.7)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) next-intl: specifier: ^4.13.0 - version: 4.13.0(next@16.2.6(@babel/core@7.29.7)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + version: 4.13.0(next@16.2.6(@babel/core@7.29.7)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(typescript@6.0.3) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -229,17 +229,17 @@ importers: specifier: 19.2.6 version: 19.2.6 react-day-picker: - specifier: ^9.14.0 - version: 9.14.0(react@19.2.6) + specifier: ^10.0.1 + version: 10.0.1(@types/react@19.2.16)(react@19.2.6) react-dom: specifier: 19.2.6 version: 19.2.6(react@19.2.6) react-hook-form: - specifier: ^7.76.1 - version: 7.76.1(react@19.2.6) + specifier: ^7.77.0 + version: 7.77.0(react@19.2.6) recharts: specifier: ^3.8.1 - version: 3.8.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1) + version: 3.8.1(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)(redux@5.0.1) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 @@ -257,57 +257,57 @@ importers: specifier: ^25.9.1 version: 25.9.1 '@types/react': - specifier: ^19.2.15 - version: 19.2.15 + specifier: ^19.2.16 + version: 19.2.16 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.15) + version: 19.2.3(@types/react@19.2.16) eslint: - specifier: ^9.39.4 - version: 9.39.4(jiti@2.7.0) + specifier: ^10.4.1 + version: 10.4.1(jiti@2.7.0) eslint-config-next: specifier: 16.2.6 - version: 16.2.6(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + version: 16.2.6(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) tailwindcss: specifier: ^4.3.0 version: 4.3.0 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 packages/database: dependencies: '@prisma/client': specifier: ^6.19.3 - version: 6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3) + version: 6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3) devDependencies: dotenv-cli: specifier: ^11.0.0 version: 11.0.0 eslint: - specifier: ^9.39.4 - version: 9.39.4(jiti@2.7.0) + specifier: ^10.4.1 + version: 10.4.1(jiti@2.7.0) prisma: specifier: ^6.19.3 - version: 6.19.3(typescript@5.9.3) + version: 6.19.3(typescript@6.0.3) tsconfig: specifier: workspace:* version: link:../tsconfig typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 packages/shared: devDependencies: eslint: - specifier: ^9.39.4 - version: 9.39.4(jiti@2.7.0) + specifier: ^10.4.1 + version: 10.4.1(jiti@2.7.0) prettier: specifier: ^3.8.3 version: 3.8.3 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 packages/tsconfig: {} @@ -533,37 +533,38 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/eslintrc@3.3.3': resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.4': - resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -647,89 +648,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -1151,6 +1168,9 @@ packages: '@next/eslint-plugin-next@16.2.6': resolution: {integrity: sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==} + '@next/eslint-plugin-next@16.2.7': + resolution: {integrity: sha512-VbS+QgMHqvIDMTIqD2xMBKK1otIpdAUKA8VLHFwR9h6OfU/mOm7w/69nQcvdmI8hCk99Wr2AsGLn/PJ/tMHw1w==} + '@next/swc-darwin-arm64@16.2.6': resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==} engines: {node: '>= 10'} @@ -1168,24 +1188,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@16.2.6': resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@16.2.6': resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@16.2.6': resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@16.2.6': resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==} @@ -1256,36 +1280,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} @@ -1853,36 +1883,42 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.15.40': resolution: {integrity: sha512-4z0MgHU+7M0pZDqBN1El7mFXDI1SBwinfcUkAyA4v8QrhOIUOZltySt2aStQLZGrdXVXM4Y4ylfiTC04ED+MoQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-ppc64-gnu@1.15.40': resolution: {integrity: sha512-fLI4iUgeSZu0eRWUXwe6YzPFx9gHbFiPkl8Rp3mJfP8OpNR3nTQCGPvHdDh9xniW7mVvgMY4ni7A4VzqI1KrpA==} engines: {node: '>=10'} cpu: [ppc64] os: [linux] + libc: [glibc] '@swc/core-linux-s390x-gnu@1.15.40': resolution: {integrity: sha512-YqeKMAb7d4nQSGMJQ454IlaCENpzcDqhvBE9+CPfdnYpnUXxd+BSrB6Xk0YjW8UyoEhUj4p6quATCxbsp6J3jg==} engines: {node: '>=10'} cpu: [s390x] os: [linux] + libc: [glibc] '@swc/core-linux-x64-gnu@1.15.40': resolution: {integrity: sha512-7HOuS1iGcme/j/TuL1TfmmLGiMQrjv/GmjyZeydl00FKPtpGXEldwqfI56xgd1YzrzoB2svWjxbGGyQ0TEASxg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.15.40': resolution: {integrity: sha512-h4kZYHc7dpc9P9u4brRJaS8Pl7tPVHAeiLSzw7T5RfIJgAoSdaCMKzI/2Uay9gFhaw8uyCDl0L5q37r0EpAfIA==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.15.40': resolution: {integrity: sha512-+mQgKZXSj6mV38Zh05QaxSjUDmGP/R2JWlXZTDLSPkDzHU6p3GxN9eeSf5dfyDVU86946fmCvSzyl/ucImx8+A==} @@ -1920,10 +1956,6 @@ packages: '@swc/types@0.1.26': resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==} - '@tabby_ai/hijri-converter@1.0.5': - resolution: {integrity: sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==} - engines: {node: '>=16.0.0'} - '@tailwindcss/node@4.3.0': resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} @@ -1962,24 +1994,28 @@ packages: engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.3.0': resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.3.0': resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.3.0': resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.3.0': resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} @@ -2126,6 +2162,9 @@ packages: '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -2188,8 +2227,8 @@ packages: peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.15': - resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} + '@types/react@19.2.16': + resolution: {integrity: sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==} '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} @@ -2203,8 +2242,8 @@ packages: '@types/superagent@8.1.10': resolution: {integrity: sha512-nbt4IWXABhW0jGmmpRzCFNlbmwCTzZ2gTUsNIr+X+ItdqPms+PAJZbWsNzpS2USqXjcoNLQcO6nXo60zcPQiIg==} - '@types/supertest@6.0.3': - resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + '@types/supertest@7.2.0': + resolution: {integrity: sha512-uh2Lv57xvggst6lCqNdFAmDSvoMG7M/HDtX4iUCquxQ5EGPtaPM5PL5Hmi7LCvOG8db7YaCPNJEeoI8s/WzIQw==} '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} @@ -2218,63 +2257,63 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.60.0': - resolution: {integrity: sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==} + '@typescript-eslint/eslint-plugin@8.60.1': + resolution: {integrity: sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.60.0 + '@typescript-eslint/parser': ^8.60.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.60.0': - resolution: {integrity: sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==} + '@typescript-eslint/parser@8.60.1': + resolution: {integrity: sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.60.0': - resolution: {integrity: sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==} + '@typescript-eslint/project-service@8.60.1': + resolution: {integrity: sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.60.0': - resolution: {integrity: sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==} + '@typescript-eslint/scope-manager@8.60.1': + resolution: {integrity: sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.60.0': - resolution: {integrity: sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==} + '@typescript-eslint/tsconfig-utils@8.60.1': + resolution: {integrity: sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.60.0': - resolution: {integrity: sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==} + '@typescript-eslint/type-utils@8.60.1': + resolution: {integrity: sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.60.0': - resolution: {integrity: sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==} + '@typescript-eslint/types@8.60.1': + resolution: {integrity: sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.60.0': - resolution: {integrity: sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==} + '@typescript-eslint/typescript-estree@8.60.1': + resolution: {integrity: sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.60.0': - resolution: {integrity: sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==} + '@typescript-eslint/utils@8.60.1': + resolution: {integrity: sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.60.0': - resolution: {integrity: sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==} + '@typescript-eslint/visitor-keys@8.60.1': + resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.1': @@ -2319,51 +2358,61 @@ packages: resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.12.2': resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} cpu: [loong64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-loong64-musl@1.12.2': resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} cpu: [loong64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.12.2': resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.12.2': resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-openharmony-arm64@1.12.2': resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} @@ -2608,8 +2657,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.11.4: - resolution: {integrity: sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==} + axe-core@4.12.0: + resolution: {integrity: sha512-FTavr/7Ba0IptwGOPxnQvdyW2tAsdLBMTBXz7rKH6xJ2skpyxpBxyHkDdBs4lf69yRqYpkqCdfhnwS8YULGOmg==} engines: {node: '>=4'} axobject-query@4.1.0: @@ -2651,8 +2700,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.32: - resolution: {integrity: sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==} + baseline-browser-mapping@2.10.33: + resolution: {integrity: sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==} engines: {node: '>=6.0.0'} hasBin: true @@ -2780,8 +2829,8 @@ packages: class-transformer@0.5.1: resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} - class-validator@0.14.4: - resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==} + class-validator@0.15.1: + resolution: {integrity: sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==} class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -2978,11 +3027,8 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - date-fns-jalali@4.1.0-0: - resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} - - date-fns@4.3.0: - resolution: {integrity: sha512-OYcL+3N/jyWbYdFGqoMAhytDgxP9pbYPUUiRCOgn4Fewaadk9l/Wam4Avciiyp2BgkpfQyBV9B+ehnVJych+eQ==} + date-fns@4.4.0: + resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -3106,8 +3152,8 @@ packages: effect@3.21.0: resolution: {integrity: sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==} - electron-to-chromium@1.5.363: - resolution: {integrity: sha512-VjUKPyWzGnT1fujlkEGC/BvN70Hh70KXtAqcmniXviYlJC/ivcT+BWGPyxWVbJZLfvtKR6dqg1L7T7pgAMBtWA==} + electron-to-chromium@1.5.366: + resolution: {integrity: sha512-OlRuhb688YTCzzU3gXPLn6nGyd+F+53INE1qaKKlu6kETErE8FYsyDh0XqXEU+uBRn0MpCzz2vfNwORhkap8qg==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -3127,8 +3173,8 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - enhanced-resolve@5.22.1: - resolution: {integrity: sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==} + enhanced-resolve@5.22.2: + resolution: {integrity: sha512-0rxICaFZ7NQho/sHely2bvOPRP0Eu2B0NZ9zM54YvRvWMn7jfz3DmnOZDR9LlXDdDcqntAVc6Hfy4gr/tdH/Ag==} engines: {node: '>=10.13.0'} error-ex@1.3.4: @@ -3285,9 +3331,9 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} @@ -3301,9 +3347,9 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@9.39.4: - resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@10.4.1: + resolution: {integrity: sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: jiti: '*' @@ -3315,6 +3361,10 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -4019,6 +4069,10 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + hasBin: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -4086,8 +4140,8 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libphonenumber-js@1.13.3: - resolution: {integrity: sha512-xMkdAMqcyG7iN2WZZmGIfWbYxW4orRkny+0/AXIbwL0xll2zkDX0Vzo/BXFa6+7mh2UvJl9MbcTtHk0YXkFtBA==} + libphonenumber-js@1.13.5: + resolution: {integrity: sha512-7/kRezHmQlMfO6pmvt34orO/g3j1C47k8FCBXFgj/mklTLwQdBca1LkhDK6RM8UyM6JqHFAIikMdkKkyfQy39A==} lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} @@ -4124,24 +4178,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -4199,9 +4257,6 @@ packages: lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} @@ -4226,8 +4281,8 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.563.0: - resolution: {integrity: sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==} + lucide-react@1.17.0: + resolution: {integrity: sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4429,8 +4484,8 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.46: - resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} + node-releases@2.0.47: + resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} engines: {node: '>=18'} normalize-path@3.0.0: @@ -4692,19 +4747,23 @@ packages: rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} - react-day-picker@9.14.0: - resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} + react-day-picker@10.0.1: + resolution: {integrity: sha512-eNh6BlwcYInWaJtRv18mXQ06Ys/H6rdTZAnTaSdOYJuTpwP1JMCHNd1FDRadA+gbeinq+psdULN5Xnowy9mV8w==} engines: {node: '>=18'} peerDependencies: + '@types/react': '>=16.8.0' react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true react-dom@19.2.6: resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} peerDependencies: react: ^19.2.6 - react-hook-form@7.76.1: - resolution: {integrity: sha512-rYM7tPiWlu3nZchkR/ex7piyzui2vFPyaLnXnI/RnblB/L4qfMmyses8llJVtF1NpE9WBBsJlGtcSZzPCXW1qQ==} + react-hook-form@7.77.0: + resolution: {integrity: sha512-Sslh9YDYc0GDlWT/lxasnIduNo4v3yyvqRGvmGKUre5AFjDs/HV9/OafHGD8d+sB2yoL4UIL9L8X9i0WlZZebg==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -4715,8 +4774,8 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-is@19.2.6: - resolution: {integrity: sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==} + react-is@19.2.7: + resolution: {integrity: sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==} react-redux@9.3.0: resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} @@ -5170,12 +5229,12 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tinyexec@1.2.2: - resolution: {integrity: sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} tmpl@1.0.5: @@ -5226,12 +5285,16 @@ packages: jest-util: optional: true - ts-loader@9.5.7: - resolution: {integrity: sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==} + ts-loader@9.6.0: + resolution: {integrity: sha512-dsJO0S+T7grTDWTc4a0nTygXGjKncVUpx8Y+af8EvI/D5WgTJby5UEk5eoMCB9EcLQmnvitqh99MqtjtHgAwFQ==} engines: {node: '>=12.0.0'} peerDependencies: + loader-utils: '*' typescript: '*' - webpack: ^5.0.0 + webpack: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + loader-utils: + optional: true ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} @@ -5308,8 +5371,8 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.60.0: - resolution: {integrity: sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==} + typescript-eslint@8.60.1: + resolution: {integrity: sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -5320,6 +5383,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -5779,26 +5847,26 @@ snapshots: tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.4.1(jiti@2.7.0))': dependencies: - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.2': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 2.1.7 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 3.1.5 + minimatch: 10.2.5 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.4.2': + '@eslint/config-helpers@0.6.0': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 - '@eslint/core@0.17.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 @@ -5810,33 +5878,21 @@ snapshots: globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.1 + js-yaml: 4.2.0 minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.4': {} + '@eslint/js@10.0.1(eslint@10.4.1(jiti@2.7.0))': + optionalDependencies: + eslint: 10.4.1(jiti@2.7.0) - '@eslint/object-schema@2.1.7': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.4.1': + '@eslint/plugin-kit@0.7.2': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 levn: 0.4.1 '@floating-ui/core@1.7.5': @@ -5868,10 +5924,10 @@ snapshots: dependencies: '@formatjs/fast-memoize': 3.1.5 - '@hookform/resolvers@5.4.0(react-hook-form@7.76.1(react@19.2.6))': + '@hookform/resolvers@5.4.0(react-hook-form@7.77.0(react@19.2.6))': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.76.1(react@19.2.6) + react-hook-form: 7.77.0(react@19.2.6) '@humanfs/core@0.19.2': dependencies: @@ -6154,7 +6210,7 @@ snapshots: jest-util: 30.4.1 slash: 3.0.0 - '@jest/core@30.4.2(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3))': + '@jest/core@30.4.2(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3))': dependencies: '@jest/console': 30.4.1 '@jest/pattern': 30.4.0 @@ -6170,7 +6226,7 @@ snapshots: fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 jest-changed-files: 30.4.1 - jest-config: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)) + jest-config: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)) jest-haste-map: 30.4.1 jest-message-util: 30.4.1 jest-regex-util: 30.4.0 @@ -6401,7 +6457,7 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: file-type: 21.3.4 iterare: 1.2.1 @@ -6412,21 +6468,21 @@ snapshots: uid: 2.0.2 optionalDependencies: class-transformer: 0.5.1 - class-validator: 0.14.4 + class-validator: 0.15.1 transitivePeerDependencies: - supports-color - '@nestjs/config@4.0.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + '@nestjs/config@4.0.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) dotenv: 17.4.1 dotenv-expand: 12.0.3 lodash: 4.18.1 rxjs: 7.8.2 - '@nestjs/core@11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -6436,31 +6492,31 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) + '@nestjs/platform-express': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) - '@nestjs/jwt@11.0.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))': + '@nestjs/jwt@11.0.2(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))': dependencies: - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@types/jsonwebtoken': 9.0.10 jsonwebtoken: 9.0.3 - '@nestjs/mapped-types@2.1.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + '@nestjs/mapped-types@2.1.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 optionalDependencies: class-transformer: 0.5.1 - class-validator: 0.14.4 + class-validator: 0.15.1 - '@nestjs/passport@11.0.5(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': + '@nestjs/passport@11.0.5(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': dependencies: - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) passport: 0.7.0 - '@nestjs/platform-express@11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)': + '@nestjs/platform-express@11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)': dependencies: - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.6 express: 5.2.1 multer: 2.1.1 @@ -6482,12 +6538,25 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + '@nestjs/schematics@11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@6.0.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + comment-json: 5.0.0 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 6.0.3 + optionalDependencies: + prettier: 3.8.3 + transitivePeerDependencies: + - chokidar + + '@nestjs/swagger@11.4.4(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.16.0 - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/mapped-types': 2.1.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.1(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) js-yaml: 4.1.1 lodash: 4.18.1 path-to-regexp: 8.4.2 @@ -6495,15 +6564,15 @@ snapshots: swagger-ui-dist: 5.32.6 optionalDependencies: class-transformer: 0.5.1 - class-validator: 0.14.4 + class-validator: 0.15.1 - '@nestjs/testing@11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/platform-express@11.1.24)': + '@nestjs/testing@11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/platform-express@11.1.24)': dependencies: - '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) + '@nestjs/platform-express': 11.1.24(@nestjs/common@11.1.24(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) '@next/env@16.2.6': {} @@ -6511,6 +6580,10 @@ snapshots: dependencies: fast-glob: 3.3.1 + '@next/eslint-plugin-next@16.2.7': + dependencies: + fast-glob: 3.3.1 + '@next/swc-darwin-arm64@16.2.6': optional: true @@ -6624,10 +6697,10 @@ snapshots: '@pkgr/core@0.3.6': {} - '@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)': + '@prisma/client@6.19.3(prisma@6.19.3(typescript@6.0.3))(typescript@6.0.3)': optionalDependencies: - prisma: 6.19.3(typescript@5.9.3) - typescript: 5.9.3 + prisma: 6.19.3(typescript@6.0.3) + typescript: 6.0.3 '@prisma/config@6.19.3': dependencies: @@ -6663,445 +6736,445 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-context': 1.1.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-context@1.1.2(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-context@1.1.3(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-context@1.1.3(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-id@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.16)(react@19.2.6) '@radix-ui/rect': 1.1.1 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-slot@1.2.3(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.16)(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-slot@1.2.4(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-slot@1.2.4(@types/react@19.2.16)(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.16)(react@19.2.6)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.16)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.16)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: '@radix-ui/rect': 1.1.1 react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.16)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@types/react': 19.2.16 + '@types/react-dom': 19.2.3(@types/react@19.2.16) '@radix-ui/rect@1.1.1': {} - '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.16)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 @@ -7111,7 +7184,7 @@ snapshots: reselect: 5.1.1 optionalDependencies: react: 19.2.6 - react-redux: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) + react-redux: 9.3.0(@types/react@19.2.16)(react@19.2.6)(redux@5.0.1) '@rtsao/scc@1.1.0': {} @@ -7197,12 +7270,10 @@ snapshots: dependencies: '@swc/counter': 0.1.3 - '@tabby_ai/hijri-converter@1.0.5': {} - '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.22.1 + enhanced-resolve: 5.22.2 jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 @@ -7382,6 +7453,8 @@ snapshots: '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 + '@types/esrecurse@4.3.1': {} + '@types/estree@1.0.9': {} '@types/express-serve-static-core@5.1.1': @@ -7449,11 +7522,11 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/react-dom@19.2.3(@types/react@19.2.15)': + '@types/react-dom@19.2.3(@types/react@19.2.16)': dependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - '@types/react@19.2.15': + '@types/react@19.2.16': dependencies: csstype: 3.2.3 @@ -7475,7 +7548,7 @@ snapshots: '@types/node': 25.9.1 form-data: 4.0.5 - '@types/supertest@6.0.3': + '@types/supertest@7.2.0': dependencies: '@types/methods': 1.1.4 '@types/superagent': 8.1.10 @@ -7490,95 +7563,95 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.60.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.60.0 - '@typescript-eslint/type-utils': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.60.0 - eslint: 9.39.4(jiti@2.7.0) + '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.60.1 + '@typescript-eslint/type-utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.1 + eslint: 10.4.1(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.60.0 - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/typescript-estree': 8.60.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.60.0 + '@typescript-eslint/scope-manager': 8.60.1 + '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.1 debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.60.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.60.1(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@5.9.3) - '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@6.0.3) + '@typescript-eslint/types': 8.60.1 debug: 4.4.3 - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.60.0': + '@typescript-eslint/scope-manager@8.60.1': dependencies: - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/visitor-keys': 8.60.0 + '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/visitor-keys': 8.60.1 - '@typescript-eslint/tsconfig-utils@8.60.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.60.1(typescript@6.0.3)': dependencies: - typescript: 5.9.3 + typescript: 6.0.3 - '@typescript-eslint/type-utils@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/typescript-estree': 8.60.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + eslint: 10.4.1(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.60.0': {} + '@typescript-eslint/types@8.60.1': {} - '@typescript-eslint/typescript-estree@8.60.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.60.1(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.60.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@5.9.3) - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/visitor-keys': 8.60.0 + '@typescript-eslint/project-service': 8.60.1(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.60.1(typescript@6.0.3) + '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/visitor-keys': 8.60.1 debug: 4.4.3 minimatch: 10.2.5 semver: 7.8.1 - tinyglobby: 0.2.16 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + '@typescript-eslint/utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.60.0 - '@typescript-eslint/types': 8.60.0 - '@typescript-eslint/typescript-estree': 8.60.0(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.60.1 + '@typescript-eslint/types': 8.60.1 + '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.60.0': + '@typescript-eslint/visitor-keys@8.60.1': dependencies: - '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/types': 8.60.1 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.1': {} @@ -7912,7 +7985,7 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axe-core@4.11.4: {} + axe-core@4.12.0: {} axobject-query@4.1.0: {} @@ -7974,7 +8047,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.32: {} + baseline-browser-mapping@2.10.33: {} bcrypt@6.0.0: dependencies: @@ -8020,10 +8093,10 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.32 + baseline-browser-mapping: 2.10.33 caniuse-lite: 1.0.30001793 - electron-to-chromium: 1.5.363 - node-releases: 2.0.46 + electron-to-chromium: 1.5.366 + node-releases: 2.0.47 update-browserslist-db: 1.2.3(browserslist@4.28.2) bs-logger@0.2.6: @@ -8116,10 +8189,10 @@ snapshots: class-transformer@0.5.1: {} - class-validator@0.14.4: + class-validator@0.15.1: dependencies: '@types/validator': 13.15.10 - libphonenumber-js: 1.13.3 + libphonenumber-js: 1.13.5 validator: 13.15.35 class-variance-authority@0.7.1: @@ -8219,7 +8292,7 @@ snapshots: cosmiconfig@8.3.6(typescript@5.9.3): dependencies: import-fresh: 3.3.1 - js-yaml: 4.1.1 + js-yaml: 4.2.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: @@ -8293,9 +8366,7 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - date-fns-jalali@4.1.0-0: {} - - date-fns@4.3.0: {} + date-fns@4.4.0: {} debug@3.2.7: dependencies: @@ -8392,7 +8463,7 @@ snapshots: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 - electron-to-chromium@1.5.363: {} + electron-to-chromium@1.5.366: {} emittery@0.13.1: {} @@ -8404,7 +8475,7 @@ snapshots: encodeurl@2.0.0: {} - enhanced-resolve@5.22.1: + enhanced-resolve@5.22.2: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 @@ -8526,29 +8597,29 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-next@16.2.6(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + eslint-config-next@16.2.6(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3): dependencies: '@next/eslint-plugin-next': 16.2.6 - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@10.4.1(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@10.4.1(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@10.4.1(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@10.4.1(jiti@2.7.0)) globals: 16.4.0 - typescript-eslint: 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + typescript-eslint: 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-webpack - eslint-plugin-import-x - supports-color - eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)): + eslint-config-prettier@10.1.8(eslint@10.4.1(jiti@2.7.0)): dependencies: - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) eslint-import-resolver-node@0.3.10: dependencies: @@ -8558,33 +8629,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) get-tsconfig: 4.14.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 - tinyglobby: 0.2.16 + tinyglobby: 0.2.17 unrs-resolver: 1.12.2 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@10.4.1(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): + eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) + '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@10.4.1(jiti@2.7.0)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -8593,9 +8664,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) + eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -8607,23 +8678,23 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): + eslint-plugin-jsx-a11y@6.10.2(eslint@10.4.1(jiti@2.7.0)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 array.prototype.flatmap: 1.3.3 ast-types-flow: 0.0.8 - axe-core: 4.11.4 + axe-core: 4.12.0 axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) hasown: 2.0.4 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -8632,28 +8703,28 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-prettier@5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0))(prettier@3.8.3): + eslint-plugin-prettier@5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0))(prettier@3.8.3): dependencies: - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) prettier: 3.8.3 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@2.7.0)) + eslint-config-prettier: 10.1.8(eslint@10.4.1(jiti@2.7.0)) - eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): + eslint-plugin-react-hooks@7.1.1(eslint@10.4.1(jiti@2.7.0)): dependencies: '@babel/core': 7.29.7 '@babel/parser': 7.29.7 - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) hermes-parser: 0.25.1 zod: 4.4.3 zod-validation-error: 4.0.2(zod@4.4.3) transitivePeerDependencies: - supports-color - eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): + eslint-plugin-react@7.37.5(eslint@10.4.1(jiti@2.7.0)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -8661,7 +8732,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.3.2 - eslint: 9.39.4(jiti@2.7.0) + eslint: 10.4.1(jiti@2.7.0) estraverse: 5.3.0 hasown: 2.0.4 jsx-ast-utils: 3.3.5 @@ -8680,8 +8751,10 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 - eslint-scope@8.4.0: + eslint-scope@9.1.2: dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -8691,28 +8764,25 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.4(jiti@2.7.0): + eslint@10.4.1(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.4 - '@eslint/plugin-kit': 0.4.1 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.6.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.9 ajv: 6.15.0 - chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -8723,8 +8793,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 + minimatch: 10.2.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -8738,6 +8807,12 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 + espree@11.2.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 + esprima@4.0.1: {} esquery@1.7.0: @@ -9385,15 +9460,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)): + jest-cli@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)): dependencies: - '@jest/core': 30.4.2(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)) + '@jest/core': 30.4.2(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)) '@jest/test-result': 30.4.1 '@jest/types': 30.4.1 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)) + jest-config: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)) jest-util: 30.4.1 jest-validate: 30.4.1 yargs: 17.7.2 @@ -9404,7 +9479,7 @@ snapshots: - supports-color - ts-node - jest-config@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)): + jest-config@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)): dependencies: '@babel/core': 7.29.7 '@jest/get-type': 30.1.0 @@ -9431,7 +9506,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 25.9.1 - ts-node: 10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3) + ts-node: 10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -9658,12 +9733,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)): + jest@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)): dependencies: - '@jest/core': 30.4.2(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)) + '@jest/core': 30.4.2(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)) '@jest/types': 30.4.1 import-local: 3.2.0 - jest-cli: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)) + jest-cli: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -9684,6 +9759,10 @@ snapshots: dependencies: argparse: 2.0.1 + js-yaml@4.2.0: + dependencies: + argparse: 2.0.1 + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -9758,7 +9837,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libphonenumber-js@1.13.3: {} + libphonenumber-js@1.13.5: {} lightningcss-android-arm64@1.32.0: optional: true @@ -9837,8 +9916,6 @@ snapshots: lodash.memoize@4.1.2: {} - lodash.merge@4.6.2: {} - lodash.once@4.1.1: {} lodash@4.18.1: {} @@ -9860,7 +9937,7 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@0.563.0(react@19.2.6): + lucide-react@1.17.0(react@19.2.6): dependencies: react: 19.2.6 @@ -9966,7 +10043,7 @@ snapshots: next-intl-swc-plugin-extractor@4.13.0: {} - next-intl@4.13.0(next@16.2.6(@babel/core@7.29.7)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(typescript@5.9.3): + next-intl@4.13.0(next@16.2.6(@babel/core@7.29.7)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)(typescript@6.0.3): dependencies: '@formatjs/intl-localematcher': 0.8.9 '@parcel/watcher': 2.5.6 @@ -9979,7 +10056,7 @@ snapshots: react: 19.2.6 use-intl: 4.13.0(react@19.2.6) optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - '@swc/helpers' @@ -9992,7 +10069,7 @@ snapshots: dependencies: '@next/env': 16.2.6 '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.32 + baseline-browser-mapping: 2.10.33 caniuse-lite: 1.0.30001793 postcss: 8.4.31 react: 19.2.6 @@ -10035,7 +10112,7 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.46: {} + node-releases@2.0.47: {} normalize-path@3.0.0: {} @@ -10047,7 +10124,7 @@ snapshots: dependencies: citty: 0.2.2 pathe: 2.0.3 - tinyexec: 1.2.2 + tinyexec: 1.2.4 object-assign@4.1.1: {} @@ -10255,14 +10332,14 @@ snapshots: '@jest/schemas': 30.4.1 ansi-styles: 5.2.0 react-is-18: react-is@18.3.1 - react-is-19: react-is@19.2.6 + react-is-19: react-is@19.2.7 - prisma@6.19.3(typescript@5.9.3): + prisma@6.19.3(typescript@6.0.3): dependencies: '@prisma/config': 6.19.3 '@prisma/engines': 6.19.3 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - magicast @@ -10303,20 +10380,20 @@ snapshots: defu: 6.1.7 destr: 2.0.5 - react-day-picker@9.14.0(react@19.2.6): + react-day-picker@10.0.1(@types/react@19.2.16)(react@19.2.6): dependencies: '@date-fns/tz': 1.5.0 - '@tabby_ai/hijri-converter': 1.0.5 - date-fns: 4.3.0 - date-fns-jalali: 4.1.0-0 + date-fns: 4.4.0 react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.16 react-dom@19.2.6(react@19.2.6): dependencies: react: 19.2.6 scheduler: 0.27.0 - react-hook-form@7.76.1(react@19.2.6): + react-hook-form@7.77.0(react@19.2.6): dependencies: react: 19.2.6 @@ -10324,43 +10401,43 @@ snapshots: react-is@18.3.1: {} - react-is@19.2.6: {} + react-is@19.2.7: {} - react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1): + react-redux@9.3.0(@types/react@19.2.16)(react@19.2.6)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.6 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 redux: 5.0.1 - react-remove-scroll-bar@2.3.8(@types/react@19.2.15)(react@19.2.6): + react-remove-scroll-bar@2.3.8(@types/react@19.2.16)(react@19.2.6): dependencies: react: 19.2.6 - react-style-singleton: 2.2.3(@types/react@19.2.15)(react@19.2.6) + react-style-singleton: 2.2.3(@types/react@19.2.16)(react@19.2.6) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - react-remove-scroll@2.7.2(@types/react@19.2.15)(react@19.2.6): + react-remove-scroll@2.7.2(@types/react@19.2.16)(react@19.2.6): dependencies: react: 19.2.6 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.15)(react@19.2.6) - react-style-singleton: 2.2.3(@types/react@19.2.15)(react@19.2.6) + react-remove-scroll-bar: 2.3.8(@types/react@19.2.16)(react@19.2.6) + react-style-singleton: 2.2.3(@types/react@19.2.16)(react@19.2.6) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.15)(react@19.2.6) - use-sidecar: 1.1.3(@types/react@19.2.15)(react@19.2.6) + use-callback-ref: 1.3.3(@types/react@19.2.16)(react@19.2.6) + use-sidecar: 1.1.3(@types/react@19.2.16)(react@19.2.6) optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 - react-style-singleton@2.2.3(@types/react@19.2.15)(react@19.2.6): + react-style-singleton@2.2.3(@types/react@19.2.16)(react@19.2.6): dependencies: get-nonce: 1.0.1 react: 19.2.6 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 react@19.2.6: {} @@ -10372,9 +10449,9 @@ snapshots: readdirp@4.1.2: {} - recharts@3.8.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1): + recharts@3.8.1(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.7)(react@19.2.6)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.16)(react@19.2.6)(redux@5.0.1))(react@19.2.6) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.47.0 @@ -10382,8 +10459,8 @@ snapshots: immer: 10.2.0 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-is: 19.2.6 - react-redux: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1) + react-is: 19.2.7 + react-redux: 9.3.0(@types/react@19.2.16)(react@19.2.6)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 use-sync-external-store: 1.6.0(react@19.2.6) @@ -10843,9 +10920,9 @@ snapshots: tiny-invariant@1.3.3: {} - tinyexec@1.2.2: {} + tinyexec@1.2.4: {} - tinyglobby@0.2.16: + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 @@ -10864,22 +10941,22 @@ snapshots: '@tokenizer/token': 0.3.0 ieee754: 1.2.1 - ts-api-utils@2.5.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: - typescript: 5.9.3 + typescript: 6.0.3 - ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@30.4.1)(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7))(jest-util@30.4.1)(jest@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@30.4.1)(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7))(jest-util@30.4.1)(jest@30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)))(typescript@6.0.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3)) + jest: 30.4.2(@types/node@25.9.1)(ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.8.1 type-fest: 4.41.0 - typescript: 5.9.3 + typescript: 6.0.3 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.29.7 @@ -10888,17 +10965,17 @@ snapshots: babel-jest: 30.4.1(@babel/core@7.29.7) jest-util: 30.4.1 - ts-loader@9.5.7(typescript@5.9.3)(webpack@5.106.0(@swc/core@1.15.40)): + ts-loader@9.6.0(typescript@6.0.3)(webpack@5.106.0(@swc/core@1.15.40)): dependencies: chalk: 4.1.2 - enhanced-resolve: 5.22.1 + enhanced-resolve: 5.22.2 micromatch: 4.0.8 semver: 7.8.1 source-map: 0.7.6 - typescript: 5.9.3 + typescript: 6.0.3 webpack: 5.106.0(@swc/core@1.15.40) - ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.40)(@types/node@25.9.1)(typescript@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 @@ -10912,7 +10989,7 @@ snapshots: create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 5.9.3 + typescript: 6.0.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: @@ -10921,7 +10998,7 @@ snapshots: tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 - enhanced-resolve: 5.22.1 + enhanced-resolve: 5.22.2 tapable: 2.3.3 tsconfig-paths: 4.2.0 @@ -11005,19 +11082,21 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + typescript-eslint@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.60.0(@typescript-eslint/parser@8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/parser': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.60.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.60.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) - eslint: 9.39.4(jiti@2.7.0) - typescript: 5.9.3 + '@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 transitivePeerDependencies: - supports-color typescript@5.9.3: {} + typescript@6.0.3: {} + uglify-js@3.19.3: optional: true @@ -11077,12 +11156,12 @@ snapshots: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@19.2.15)(react@19.2.6): + use-callback-ref@1.3.3(@types/react@19.2.16)(react@19.2.6): dependencies: react: 19.2.6 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 use-intl@4.13.0(react@19.2.6): dependencies: @@ -11092,13 +11171,13 @@ snapshots: intl-messageformat: 11.2.7 react: 19.2.6 - use-sidecar@1.1.3(@types/react@19.2.15)(react@19.2.6): + use-sidecar@1.1.3(@types/react@19.2.16)(react@19.2.6): dependencies: detect-node-es: 1.1.0 react: 19.2.6 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.15 + '@types/react': 19.2.16 use-sync-external-store@1.6.0(react@19.2.6): dependencies: @@ -11166,7 +11245,7 @@ snapshots: acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.2 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.22.1 + enhanced-resolve: 5.22.2 es-module-lexer: 2.1.0 eslint-scope: 5.1.1 events: 3.3.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 3ff5faa..fc7cfeb 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,15 @@ packages: - "apps/*" - "packages/*" + +allowBuilds: + '@nestjs/core': true + '@parcel/watcher': true + '@prisma/client': true + '@prisma/engines': true + '@scarf/scarf': true + '@swc/core': true + bcrypt: true + prisma: true + sharp: true + unrs-resolver: true From 0fb30c91b8f2b2397444e7ddba6d0a9ff1a2e5ce Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 5 Jun 2026 00:43:18 +0200 Subject: [PATCH 09/13] fix build issue --- .docker/Dockerfile.customer | 2 ++ .github/workflows/{ci.yml => 1-ci.yml} | 2 +- .../workflows/{docker.yml => 2-images.yml} | 23 ++++++++----------- .../workflows/{deploy.yml => 3-deploy.yml} | 6 ++--- 4 files changed, 15 insertions(+), 18 deletions(-) rename .github/workflows/{ci.yml => 1-ci.yml} (99%) rename .github/workflows/{docker.yml => 2-images.yml} (94%) rename .github/workflows/{deploy.yml => 3-deploy.yml} (97%) diff --git a/.docker/Dockerfile.customer b/.docker/Dockerfile.customer index 4269f57..b3e4457 100644 --- a/.docker/Dockerfile.customer +++ b/.docker/Dockerfile.customer @@ -38,6 +38,8 @@ RUN pnpm install --frozen-lockfile FROM base AS builder COPY --from=deps /app/node_modules ./node_modules COPY --from=pruner /app/out/full/ . +# prisma generate non richiede DATABASE_URL — legge solo lo schema e genera il client +RUN pnpm exec prisma generate --schema packages/database/prisma/schema.prisma RUN pnpm --filter customer-service build # ── Stage 4: runner ─────────────────────────────────────────────────────────── diff --git a/.github/workflows/ci.yml b/.github/workflows/1-ci.yml similarity index 99% rename from .github/workflows/ci.yml rename to .github/workflows/1-ci.yml index 4f3e3de..f1e2791 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/1-ci.yml @@ -14,7 +14,7 @@ # - I "services" (es. postgres) si definiscono dentro il job con "services:" # ───────────────────────────────────────────────────────────────────────────── -name: CI +name: "CI" # ───────────────────────────────────────────────────────────────────────────── # ON: TRIGGER diff --git a/.github/workflows/docker.yml b/.github/workflows/2-images.yml similarity index 94% rename from .github/workflows/docker.yml rename to .github/workflows/2-images.yml index 1f968eb..7bd8f75 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/2-images.yml @@ -20,22 +20,16 @@ # - develop → idem per develop # ───────────────────────────────────────────────────────────────────────────── -name: Prepare Docker images +name: "Images" on: - push: - branches: - - main - - develop - - feature/** - # Triggera solo se cambiano file rilevanti per Docker. - # Evita build inutili per modifiche a docs, test, ecc. - paths: - - "apps/**" - - "packages/**" - - ".docker/**" - - "pnpm-lock.yaml" - - "turbo.json" + # Parte solo dopo che "CI" completa con successo. + # Il paths filter non è supportato con workflow_run — la cache Docker + # rende veloce il rebuild quando non cambiano dipendenze. + workflow_run: + workflows: ["CI"] + types: [completed] + branches: [main, develop, feature/**] # ───────────────────────────────────────────────────────────────────────────── # CONCURRENCY @@ -62,6 +56,7 @@ jobs: # ─────────────────────────────────────────────────────────────────────────── build-and-push: name: Build ${{ matrix.app }} + if: github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/deploy.yml b/.github/workflows/3-deploy.yml similarity index 97% rename from .github/workflows/deploy.yml rename to .github/workflows/3-deploy.yml index e125bd3..e28c40e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/3-deploy.yml @@ -2,7 +2,7 @@ # DEPLOY — SSH deploy su server self-hosted dopo build Docker # # TRIGGER: workflow_run -# Parte quando "Prepare Docker images" completa con successo su main/develop. +# Parte quando "Images" completa con successo su main/develop. # Garantisce che le immagini GHCR siano disponibili prima di deployare. # # DUE AMBIENTI: @@ -22,11 +22,11 @@ # - ~/visit-notebook/.env con le variabili d'ambiente di produzione # ───────────────────────────────────────────────────────────────────────────── -name: Deploy +name: "3. Deploy" on: workflow_run: - workflows: ["Prepare Docker images"] + workflows: ["Images"] types: [completed] branches: [main, develop] From 3ca3bd353bf510184c0f01cc4802100e57bdbddb Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 5 Jun 2026 00:48:29 +0200 Subject: [PATCH 10/13] fix lint issues --- apps/web/package.json | 2 +- package.json | 4 +- pnpm-lock.yaml | 252 +++++++++++++++++++++++++++++++----------- 3 files changed, 191 insertions(+), 67 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 2a743dd..e7ec1d3 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -47,7 +47,7 @@ "@types/node": "^25.9.1", "@types/react": "^19.2.16", "@types/react-dom": "^19.2.3", - "eslint": "^10.4.1", + "eslint": "^9.0.0", "eslint-config-next": "16.2.6", "tailwindcss": "^4.3.0", "typescript": "^6.0.3" diff --git a/package.json b/package.json index cceddda..ba76937 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,9 @@ "db:studio": "turbo db:studio" }, "devDependencies": { - "@eslint/js": "^10.0.1", + "@eslint/js": "^9.0.0", "@next/eslint-plugin-next": "^16.2.7", - "eslint": "^10.4.1", + "eslint": "^9.0.0", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.1.1", "prettier": "^3.8.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 774c883..eafdc31 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,20 +9,20 @@ importers: .: devDependencies: '@eslint/js': - specifier: ^10.0.1 - version: 10.0.1(eslint@10.4.1(jiti@2.7.0)) + specifier: ^9.0.0 + version: 9.39.4 '@next/eslint-plugin-next': specifier: ^16.2.7 version: 16.2.7 eslint: - specifier: ^10.4.1 - version: 10.4.1(jiti@2.7.0) + specifier: ^9.0.0 + version: 9.39.4(jiti@2.7.0) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@10.4.1(jiti@2.7.0)) + version: 7.37.5(eslint@9.39.4(jiti@2.7.0)) eslint-plugin-react-hooks: specifier: ^7.1.1 - version: 7.1.1(eslint@10.4.1(jiti@2.7.0)) + version: 7.1.1(eslint@9.39.4(jiti@2.7.0)) prettier: specifier: ^3.8.3 version: 3.8.3 @@ -34,7 +34,7 @@ importers: version: 2.9.16 typescript-eslint: specifier: ^8.60.1 - version: 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + version: 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) apps/customer-service: dependencies: @@ -263,11 +263,11 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.16) eslint: - specifier: ^10.4.1 - version: 10.4.1(jiti@2.7.0) + specifier: ^9.0.0 + version: 9.39.4(jiti@2.7.0) eslint-config-next: specifier: 16.2.6 - version: 16.2.6(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + version: 16.2.6(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) tailwindcss: specifier: ^4.3.0 version: 4.3.0 @@ -533,14 +533,26 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.23.5': resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-helpers@0.6.0': resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.2.1': resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -549,19 +561,26 @@ packages: resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@10.0.1': - resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - peerDependencies: - eslint: ^10.0.0 - peerDependenciesMeta: - eslint: - optional: true + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@3.0.5': resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.7.2': resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -3331,6 +3350,10 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@9.1.2: resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -3357,6 +3380,16 @@ packages: jiti: optional: true + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4257,6 +4290,9 @@ packages: lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} @@ -5852,8 +5888,21 @@ snapshots: eslint: 10.4.1(jiti@2.7.0) eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.2': {} + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + '@eslint/config-array@0.23.5': dependencies: '@eslint/object-schema': 3.0.5 @@ -5862,10 +5911,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + '@eslint/config-helpers@0.6.0': dependencies: '@eslint/core': 1.2.1 + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 @@ -5884,12 +5941,31 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@10.0.1(eslint@10.4.1(jiti@2.7.0))': - optionalDependencies: - eslint: 10.4.1(jiti@2.7.0) + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.2.0 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} '@eslint/object-schema@3.0.5': {} + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + '@eslint/plugin-kit@0.7.2': dependencies: '@eslint/core': 1.2.1 @@ -7563,15 +7639,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.60.1 - '@typescript-eslint/type-utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/type-utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.60.1 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -7579,14 +7655,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.60.1 '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.60.1 debug: 4.4.3 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -7609,13 +7685,13 @@ snapshots: dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) debug: 4.4.3 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: @@ -7638,13 +7714,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + '@typescript-eslint/utils@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@typescript-eslint/scope-manager': 8.60.1 '@typescript-eslint/types': 8.60.1 '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -8597,18 +8673,18 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-next@16.2.6(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3): + eslint-config-next@16.2.6(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): dependencies: '@next/eslint-plugin-next': 16.2.6 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@10.4.1(jiti@2.7.0)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@10.4.1(jiti@2.7.0)) - eslint-plugin-react: 7.37.5(eslint@10.4.1(jiti@2.7.0)) - eslint-plugin-react-hooks: 7.1.1(eslint@10.4.1(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) globals: 16.4.0 - typescript-eslint: 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + typescript-eslint: 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: @@ -8629,33 +8705,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) get-tsconfig: 4.14.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.17 unrs-resolver: 1.12.2 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@10.4.1(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)): + eslint-module-utils@2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) - eslint: 10.4.1(jiti@2.7.0) + '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@10.4.1(jiti@2.7.0)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -8664,9 +8740,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)))(eslint@10.4.1(jiti@2.7.0)) + eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)))(eslint@9.39.4(jiti@2.7.0)) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -8678,13 +8754,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@10.4.1(jiti@2.7.0)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 @@ -8694,7 +8770,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) hasown: 2.0.4 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -8713,18 +8789,18 @@ snapshots: '@types/eslint': 9.6.1 eslint-config-prettier: 10.1.8(eslint@10.4.1(jiti@2.7.0)) - eslint-plugin-react-hooks@7.1.1(eslint@10.4.1(jiti@2.7.0)): + eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): dependencies: '@babel/core': 7.29.7 '@babel/parser': 7.29.7 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) hermes-parser: 0.25.1 zod: 4.4.3 zod-validation-error: 4.0.2(zod@4.4.3) transitivePeerDependencies: - supports-color - eslint-plugin-react@7.37.5(eslint@10.4.1(jiti@2.7.0)): + eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -8732,7 +8808,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.3.2 - eslint: 10.4.1(jiti@2.7.0) + eslint: 9.39.4(jiti@2.7.0) estraverse: 5.3.0 hasown: 2.0.4 jsx-ast-utils: 3.3.5 @@ -8751,6 +8827,11 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 @@ -8801,6 +8882,47 @@ snapshots: transitivePeerDependencies: - supports-color + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + espree@10.4.0: dependencies: acorn: 8.16.0 @@ -9916,6 +10038,8 @@ snapshots: lodash.memoize@4.1.2: {} + lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} lodash@4.18.1: {} @@ -11082,13 +11206,13 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3): + typescript-eslint@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/parser': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/eslint-plugin': 8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) '@typescript-eslint/typescript-estree': 8.60.1(typescript@6.0.3) - '@typescript-eslint/utils': 8.60.1(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) - eslint: 10.4.1(jiti@2.7.0) + '@typescript-eslint/utils': 8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) + eslint: 9.39.4(jiti@2.7.0) typescript: 6.0.3 transitivePeerDependencies: - supports-color From 44686015cb3aa90fff9e04a2e768ed8937b6faf0 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 5 Jun 2026 00:55:17 +0200 Subject: [PATCH 11/13] fix unit tests --- .github/workflows/1-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/1-ci.yml b/.github/workflows/1-ci.yml index f1e2791..e0156ee 100644 --- a/.github/workflows/1-ci.yml +++ b/.github/workflows/1-ci.yml @@ -234,6 +234,9 @@ jobs: with: name: build-output + - name: Generate Prisma client + run: pnpm exec prisma generate --schema packages/database/prisma/schema.prisma + - name: Run unit tests run: pnpm --filter customer-service test @@ -298,6 +301,9 @@ jobs: with: name: build-output + - name: Generate Prisma client + run: pnpm exec prisma generate --schema packages/database/prisma/schema.prisma + - name: Run E2E tests run: pnpm --filter customer-service test:e2e continue-on-error: true # equivalente a "allow_failure: true" in GitLab From 2879e744493306989180c5e1928f5e8125e3a7b2 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 5 Jun 2026 00:59:42 +0200 Subject: [PATCH 12/13] fix unit tests --- .github/workflows/1-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/1-ci.yml b/.github/workflows/1-ci.yml index e0156ee..0e95747 100644 --- a/.github/workflows/1-ci.yml +++ b/.github/workflows/1-ci.yml @@ -235,7 +235,7 @@ jobs: name: build-output - name: Generate Prisma client - run: pnpm exec prisma generate --schema packages/database/prisma/schema.prisma + run: pnpm --filter @notebook/postgres exec prisma generate - name: Run unit tests run: pnpm --filter customer-service test @@ -302,7 +302,7 @@ jobs: name: build-output - name: Generate Prisma client - run: pnpm exec prisma generate --schema packages/database/prisma/schema.prisma + run: pnpm --filter @notebook/postgres exec prisma generate - name: Run E2E tests run: pnpm --filter customer-service test:e2e From 2eb1dd4c42505bfc40e3b5a40c2c07dace015577 Mon Sep 17 00:00:00 2001 From: Marco Baldassarri Date: Fri, 5 Jun 2026 01:14:13 +0200 Subject: [PATCH 13/13] update when cicd triggers --- .github/workflows/1-ci.yml | 89 +--------------------------------- .github/workflows/2-images.yml | 63 +----------------------- .github/workflows/3-deploy.yml | 46 +----------------- 3 files changed, 5 insertions(+), 193 deletions(-) diff --git a/.github/workflows/1-ci.yml b/.github/workflows/1-ci.yml index 0e95747..460e865 100644 --- a/.github/workflows/1-ci.yml +++ b/.github/workflows/1-ci.yml @@ -1,35 +1,14 @@ -# ───────────────────────────────────────────────────────────────────────────── -# CONCETTI BASE DI GITHUB ACTIONS -# -# Workflow = file YAML in .github/workflows/ — equivalente alla pipeline GitLab -# Job = unità di esecuzione che gira su un runner (VM) — equivalente al job GitLab -# Step = singolo comando dentro un job — equivalente a una riga di "script:" -# Action = step riutilizzabile pubblicato su GitHub Marketplace (es. actions/checkout) -# -# DIFFERENZE CHIAVE rispetto a GitLab CI: -# - Non esistono "stage" espliciti: l'ordine si controlla con "needs:" -# - Ogni job gira su una VM FRESCA (non c'è stato condiviso automaticamente) -# - La cache si gestisce con actions/cache (non è automatica come in GitLab) -# - Gli artifact si passano con actions/upload-artifact / download-artifact -# - I "services" (es. postgres) si definiscono dentro il job con "services:" -# ───────────────────────────────────────────────────────────────────────────── - name: "CI" -# ───────────────────────────────────────────────────────────────────────────── -# ON: TRIGGER -# ───────────────────────────────────────────────────────────────────────────── on: push: branches: - main - develop - - feature/** # tutte le feature branch (opzionale, dipende dal tuo workflow) pull_request: branches: - main - develop - - feature/** workflow_dispatch: env: @@ -39,38 +18,7 @@ env: PNPM_VERSION: "11.5.1" NODE_VERSION: "24" -# ───────────────────────────────────────────────────────────────────────────── -# PERCHÉ NON PASSIAMO node_modules COME ARTIFACT? -# -# actions/upload-artifact zippa i file ma NON preserva i permessi eseguibili. -# I binari in node_modules/.bin/ (turbo, eslint, tsc, ecc.) diventano -# file normali → "command not found" quando provi a eseguirli. -# -# SOLUZIONE: ogni job fa "pnpm install --frozen-lockfile" da solo. -# È veloce perché actions/cache salva lo store pnpm (~/.pnpm-store) che -# contiene i pacchetti già scaricati. pnpm ricrea node_modules in secondi -# senza ri-scaricare nulla dalla rete. -# -# ECCEZIONE: i build artifact (apps/web/.next, dist/, .prisma) NON sono -# binari con permessi speciali, quindi si possono passare tranquillamente. -# ───────────────────────────────────────────────────────────────────────────── - jobs: - - # ───────────────────────────────────────────────────────────────────────── - # ANCHOR YAML PER SETUP COMUNE - # GitHub Actions non supporta YAML anchors (&/*) nativamente. - # L'approccio standard è ripetere i step di setup in ogni job - # (oppure usare "composite actions" in file separati per DRY avanzato). - # - # Qui commentiamo il pattern una volta e lo ripetiamo — è normale in GHA. - # ───────────────────────────────────────────────────────────────────────── - - # ───────────────────────────────────────────────────────────────────────── - # JOB 1: lint - # Non ha "needs:" → parte subito. Stesso per "typecheck". - # I due job girano in PARALLELO perché non si aspettano a vicenda. - # ───────────────────────────────────────────────────────────────────────── lint: name: Lint runs-on: ubuntu-latest @@ -89,10 +37,6 @@ jobs: with: version: ${{ env.PNPM_VERSION }} - # ── Cache dello store pnpm ───────────────────────────────────────────── - # ~/.pnpm-store contiene i pacchetti scaricati (come la cache di npm/yarn). - # Se la cache esiste: pnpm install non scarica nulla dalla rete. - # Se non esiste (prima run o lockfile cambiato): scarica tutto e salva. - name: Cache pnpm store uses: actions/cache@v4 with: @@ -101,17 +45,12 @@ jobs: restore-keys: | pnpm-${{ runner.os }}- - # pnpm ricrea node_modules dallo store locale — in genere < 30 secondi - name: Install dependencies run: pnpm install --frozen-lockfile - name: Lint run: pnpm lint - # ───────────────────────────────────────────────────────────────────────── - # JOB 2: typecheck - # Parallelo a "lint" — nessun "needs:", parte contemporaneamente. - # ───────────────────────────────────────────────────────────────────────── typecheck: name: Typecheck runs-on: ubuntu-latest @@ -144,11 +83,6 @@ jobs: - name: Typecheck run: pnpm typecheck - # ───────────────────────────────────────────────────────────────────────── - # JOB 3: build - # "needs: [lint, typecheck]" = aspetta che ENTRAMBI passino. - # Se uno fallisce, questo job non parte (e non spreca minuti di runner). - # ───────────────────────────────────────────────────────────────────────── build: name: Build runs-on: ubuntu-latest @@ -182,10 +116,6 @@ jobs: - name: Build all packages run: pnpm build - # ── Build artifact ──────────────────────────────────────────────────── - # Questi file NON sono eseguibili con permessi speciali: si possono - # passare come artifact senza problemi di permessi. - # I job di test li scaricano per non dover rifare il build. - name: Upload build artifacts uses: actions/upload-artifact@v4 with: @@ -196,9 +126,6 @@ jobs: packages/database/node_modules/.prisma retention-days: 1 - # ───────────────────────────────────────────────────────────────────────── - # JOB 4: test-unit - # ───────────────────────────────────────────────────────────────────────── test-unit: name: Unit Tests runs-on: ubuntu-latest @@ -240,14 +167,6 @@ jobs: - name: Run unit tests run: pnpm --filter customer-service test - # ───────────────────────────────────────────────────────────────────────── - # JOB 5: test-e2e - # Parallelo a "test-unit" (stesso "needs: [build]"). - # - # DIFFERENZA HOSTNAME SERVICES: - # GitLab: "alias: postgres" → hostname "postgres" - # GitHub: sempre "localhost" (+ ports: mapping obbligatorio) - # ───────────────────────────────────────────────────────────────────────── test-e2e: name: E2E Tests runs-on: ubuntu-latest @@ -306,12 +225,8 @@ jobs: - name: Run E2E tests run: pnpm --filter customer-service test:e2e - continue-on-error: true # equivalente a "allow_failure: true" in GitLab - - # ───────────────────────────────────────────────────────────────────────── - # JOB 6: security-audit - # Parte in parallelo a lint/typecheck — non serve aspettare il build. - # ───────────────────────────────────────────────────────────────────────── + continue-on-error: true + security-audit: name: Security Audit runs-on: ubuntu-latest diff --git a/.github/workflows/2-images.yml b/.github/workflows/2-images.yml index 7bd8f75..07b1fd8 100644 --- a/.github/workflows/2-images.yml +++ b/.github/workflows/2-images.yml @@ -1,42 +1,11 @@ -# ───────────────────────────────────────────────────────────────────────────── -# DOCKER — build e push immagini su GitHub Container Registry (GHCR) -# -# GHCR è il registry Docker integrato in GitHub, gratuito per repo pubblici. -# Le immagini sono accessibili su: ghcr.io/// -# -# PERCHÉ NON docker compose build? -# - docker compose non supporta BuildKit cache per-layer su GHA -# - meno controllo sui tag (sha, branch, latest) -# - docker/build-push-action è lo standard GHA: BuildKit nativo, cache GHA -# -# CACHE STRATEGIA (type=gha): -# - GHA salva i layer Docker tra una run e l'altra -# - Se cambiano solo i sorgenti (non le dipendenze), lo stage "deps" è cached -# - Prima run: ~5 min. Run successive con solo code changes: ~2 min. -# -# TAG STRATEGIA: -# - sha- → tag immutabile per ogni commit (es. sha-abc1234) -# - main → tag mobile che punta all'ultimo commit su main -# - develop → idem per develop -# ───────────────────────────────────────────────────────────────────────────── - name: "Images" on: - # Parte solo dopo che "CI" completa con successo. - # Il paths filter non è supportato con workflow_run — la cache Docker - # rende veloce il rebuild quando non cambiano dipendenze. workflow_run: workflows: ["CI"] types: [completed] - branches: [main, develop, feature/**] + branches: [main, develop] -# ───────────────────────────────────────────────────────────────────────────── -# CONCURRENCY -# Se arrivano due push in rapida successione sullo stesso branch, -# cancella la run precedente e parte con quella nuova. -# Evita di sprecare minuti runner su build già superate. -# ───────────────────────────────────────────────────────────────────────────── concurrency: group: docker-${{ github.ref }} cancel-in-progress: true @@ -45,15 +14,6 @@ env: REGISTRY: ghcr.io jobs: - # ─────────────────────────────────────────────────────────────────────────── - # MATRIX BUILD - # Un solo job con strategy.matrix costruisce entrambe le immagini IN PARALLELO. - # Aggiungere una terza app = aggiungere una riga alla matrix, nient'altro. - # - # matrix.include permette di specificare parametri diversi per ogni app: - # - app: nome usato nei log e nei tag - # - dockerfile: path del Dockerfile - # ─────────────────────────────────────────────────────────────────────────── build-and-push: name: Build ${{ matrix.app }} if: github.event.workflow_run.conclusion == 'success' @@ -61,7 +21,7 @@ jobs: permissions: contents: read - packages: write # necessario per pushare su GHCR + packages: write strategy: matrix: @@ -75,15 +35,8 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - # ── docker/setup-buildx-action ────────────────────────────────────────── - # Abilita BuildKit — il builder moderno di Docker. - # Necessario per: multi-stage build paralleli, cache GHA, build cross-platform. - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - # ── docker/login-action ───────────────────────────────────────────────── - # GITHUB_TOKEN è automatico — nessun secret da configurare manualmente. - # Permette di pushare su ghcr.io//. - name: Log in to GHCR uses: docker/login-action@v3 with: @@ -91,10 +44,6 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - # ── docker/metadata-action ────────────────────────────────────────────── - # Genera i tag automaticamente in base al contesto Git. - # Output: steps.meta.outputs.tags → tutti i tag (stringa multi-riga) - # steps.meta.outputs.labels → OCI labels standard per l'immagine - name: Docker metadata id: meta uses: docker/metadata-action@v5 @@ -104,14 +53,6 @@ jobs: type=sha,prefix=sha-,format=short type=ref,event=branch - # ── docker/build-push-action ──────────────────────────────────────────── - # Build + push con BuildKit. - # - # cache-from: tenta di riutilizzare i layer dalla cache GHA - # cache-to: salva i layer nella cache GHA dopo il build - # mode=max: salva tutti i layer intermedi (anche degli stage non finali) - # → lo stage "deps" è cached anche se cambia solo il sorgente - # scope: isola la cache per app (evita collisioni tra customer e web) - name: Build and push uses: docker/build-push-action@v6 with: diff --git a/.github/workflows/3-deploy.yml b/.github/workflows/3-deploy.yml index e28c40e..c310e54 100644 --- a/.github/workflows/3-deploy.yml +++ b/.github/workflows/3-deploy.yml @@ -1,27 +1,3 @@ -# ───────────────────────────────────────────────────────────────────────────── -# DEPLOY — SSH deploy su server self-hosted dopo build Docker -# -# TRIGGER: workflow_run -# Parte quando "Images" completa con successo su main/develop. -# Garantisce che le immagini GHCR siano disponibili prima di deployare. -# -# DUE AMBIENTI: -# staging → develop → deploy automatico -# production → main → deploy con manual approval gate -# -# SECRETS (configurare in GitHub Settings → Environments): -# SSH_HOST IP o hostname del server -# SSH_USER utente SSH (es. ubuntu, deploy) -# SSH_PRIVATE_KEY chiave privata ED25519 -# GHCR_USER GitHub username (per docker login sul server) -# GHCR_TOKEN Personal Access Token con scope read:packages -# -# PREREQUISITI SUL SERVER: -# - Docker + Docker Compose installati -# - ~/visit-notebook/docker-compose.yml configurato con le immagini GHCR -# - ~/visit-notebook/.env con le variabili d'ambiente di produzione -# ───────────────────────────────────────────────────────────────────────────── - name: "3. Deploy" on: @@ -30,26 +6,16 @@ on: types: [completed] branches: [main, develop] -# ───────────────────────────────────────────────────────────────────────────── -# CONCURRENCY -# cancel-in-progress: false — non cancellare mai un deploy già in corso. -# Un deploy a metà strada lascerebbe il server in stato inconsistente. -# ───────────────────────────────────────────────────────────────────────────── concurrency: group: deploy-${{ github.event.workflow_run.head_branch }} cancel-in-progress: false jobs: - - # ─────────────────────────────────────────────────────────────────────────── - # STAGING — develop → auto deploy - # ─────────────────────────────────────────────────────────────────────────── deploy-staging: name: Deploy → Staging if: >- github.event.workflow_run.conclusion == 'success' && - (github.event.workflow_run.head_branch == 'develop' || - github.event.workflow_run.head_branch == 'feature/cicd') + github.event.workflow_run.head_branch == 'develop' runs-on: ubuntu-latest environment: staging @@ -69,16 +35,6 @@ jobs: docker compose pull docker compose up -d --remove-orphans docker image prune -f - - # ─────────────────────────────────────────────────────────────────────────── - # PRODUCTION — main → deploy con manual approval - # - # Il gate di approvazione manuale è configurato in GitHub: - # Settings → Environments → production → Required reviewers - # - # Il job si ferma qui finché qualcuno non approva dal pannello Actions. - # Pattern standard nelle aziende: nessuno deploya in prod senza review. - # ─────────────────────────────────────────────────────────────────────────── deploy-production: name: Deploy → Production if: >-