diff --git a/.env.default b/.env.default index f8c93eaf4..30a3c1ce3 100644 --- a/.env.default +++ b/.env.default @@ -41,4 +41,6 @@ POSTGRES_STATEMENT_TIMEOUT=100000 DELETE_AFTER_DAYS=30 -DEV_BUILD_CONTEXT= \ No newline at end of file +DEV_BUILD_CONTEXT= + +JWT_SECRET= \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 248744e22..d8262b0f8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,13 +6,17 @@ version: 2 updates: - package-ecosystem: "npm" # See documentation for possible values - directory: "/teammapper-backend" # Location of package manifests - schedule: - interval: "weekly" - - package-ecosystem: "npm" # See documentation for possible values - directory: "/teammapper-frontend" # Location of package manifests + directory: "/" schedule: interval: "weekly" + open-pull-requests-limit: 15 + groups: + production-dependencies: + dependency-type: "production" + update-types: ["minor", "patch"] + development-dependencies: + dependency-type: "development" + update-types: ["minor", "patch"] - package-ecosystem: "docker" # See documentation for possible values directory: "/" # Location of package manifests schedule: @@ -21,4 +25,3 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb9c5a54f..f42e7823b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: '22' @@ -48,7 +48,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: '22' @@ -64,7 +64,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: '22' @@ -80,7 +80,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: '22' @@ -97,7 +97,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: '22' @@ -126,7 +126,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: '22' @@ -154,7 +154,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: '22' diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 9f2f7c3e0..20a461602 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: lts/* - run: corepack enable @@ -53,5 +53,5 @@ jobs: if: ${{ !cancelled() }} with: name: playwright - path: playwright + path: teammapper-frontend/playwright retention-days: 7 \ No newline at end of file diff --git a/README.md b/README.md index cb390edd0..32ccae7bd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ - # TeamMapper + ![TeamMapper Screenshot](docs/teammapper-logo.png "TeamMapper Logo") Mindmapping made simple: Host and create your own mindmaps. Share your mindmap sessions with your team and collaborate on mindmaps. @@ -11,7 +11,7 @@ TeamMapper is based on mindmapp (https://github.com/cedoor/mindmapp , discontinu ## Features: - **Creation**: Host and create your own mindmaps -- **Customization**: Add images, pictograms*, colors, font properties and links to nodes +- **Customization**: Add images, pictograms\*, colors, font properties and links to nodes - **Collaboration**: Share your mindmap with friends and collegues, using either a view-only or modification invite! - **Interoperability**: Import and export functionality (JSON, Mermaid, SVG, PDF, PNG...) - **Shareability**: Use a QR Code or URL to share your maps @@ -128,6 +128,7 @@ For examples with a reverse proxy, see [documentation about deployment](docs/dep ``` ### Production + - Duplicate and rename `.env.default` ```bash @@ -162,13 +163,15 @@ For examples with a reverse proxy, see [documentation about deployment](docs/dep ```bash docker compose --file docker-compose-prod.yml --env-file .env.prod down -v ``` - + If you want to run prod migrations (again): ```bash docker compose exec app_prod pnpm --filter teammapper-backend run prod:typeorm:migrate ``` + #### Postgres and SSL + If needed, you can make the connection to Postgres more secure by using a SSL connection. - Generate self-signed ssl sertificate for the postgres server on the host machine; the generated files are mounted into the docker container @@ -206,10 +209,32 @@ Example of running sql via typeorm: docker compose --file docker-compose-prod.yml --env-file .env.prod exec app_prod pnpm --filter teammapper-backend exec typeorm query "select * from mmp_node" --dataSource ./dist/data-source.js ``` -### Frontend feature flags -See file /teammapper-frontend/src/envrionments/environment.prod.ts to configure feature flags: -- `featureFlagPictograms`: Disables/Enables the pictogram feature (default: disabled). Note: You have to set this flag before build time! -- `featureFlagAI`: Disables/Enables AI functionality like generating mindmaps with AI +### Default Settings + +The following files contain configurations for default settings: + +1. `/teammapper-backend/config/settings.dev.json` + + - Contains the default values for development mode + +2. `/teammapper-backend/config/settings.prod.json` + + - Contains the default values for production mode + - Changes here require rebuilding the Docker image + +3. `/config/settings.override.json` + - Values defined in `settings.override.json` override the values in `settings.prod.json` + - Values can be adjusted at runtime + +The settings are conceptually divided into: + +- **System Settings**: Settings provided by the application, which are not cached by the frontend and can only be adjusted in the backend +- **User Settings**: values configured by the user in the frontend, which persist separately and override system defaults where applicable. + +The settings configuration includes the following feature flags: + +- `featureFlagPictograms`: Disables/Enables the pictogram feature (default: disabled). Note: You have to set this flag before build time! +- `featureFlagAI`: Disables/Enables AI functionality like generating mindmaps with AI ### Further details @@ -242,8 +267,12 @@ The TeamMapper[logo](https://thenounproject.com/icon/188125/) in this repo – c ## Acknowledgements -- *Pictograms author: Sergio Palao. Origin: ARASAAC (http://www.arasaac.org). License: CC (BY-NC-SA). Owner: Government of Aragon (Spain) +- \*Pictograms author: Sergio Palao. Origin: ARASAAC (http://www.arasaac.org). License: CC (BY-NC-SA). Owner: Government of Aragon (Spain) - Mindmapp: https://github.com/cedoor/mindmapp (discontinued) - mmp: https://github.com/cedoor/mmp (discontinued) - D3: https://github.com/d3/d3 - DomPurify: https://github.com/cure53/DOMPurify + +``` + +``` diff --git a/config/settings.override.json b/config/settings.override.json new file mode 100644 index 000000000..738417bf8 --- /dev/null +++ b/config/settings.override.json @@ -0,0 +1,6 @@ +{ + "systemSettings": { + }, + "userSettings": { + } +} diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml index f1af5588c..6e5307e60 100644 --- a/docker-compose-prod.yml +++ b/docker-compose-prod.yml @@ -19,11 +19,14 @@ services: POSTGRES_QUERY_TIMEOUT: ${POSTGRES_QUERY_TIMEOUT:-100000} POSTGRES_STATEMENT_TIMEOUT: ${POSTGRES_STATEMENT_TIMEOUT:-100000} DELETE_AFTER_DAYS: ${DELETE_AFTER_DAYS:-30} + JWT_SECRET: ${JWT_SECRET} ports: - "${APP_PROD_PORT:-80}:3000" restart: always depends_on: - postgres_prod + volumes: + - ./config/settings.override.json:/home/node/app/teammapper-backend/config/settings.override.json:ro postgres_prod: image: postgres:15-alpine diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 6ea99e6d0..697f1ae5c 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,10 +1,10 @@ services: app: build: - context: ${DEV_BUILD_CONTEXT} + context: ${DEV_BUILD_CONTEXT}/teammapper dockerfile: Dockerfile target: development tty: true stdin_open: true volumes: - - ${DEV_BUILD_CONTEXT}/.claude:/home/node/app/.claude \ No newline at end of file + - ${DEV_BUILD_CONTEXT}/teammapper/.claude:/home/node/app/.claude \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 4b0967164..927c0fe87 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,7 @@ services: AI_LLM_RPM: ${DOCKER_COMPOSE_APP_ENV_AI_LLM_API_RPM} AI_LLM_TPM: ${DOCKER_COMPOSE_APP_ENV_AI_LLM_API_TPM} AI_LLM_TPD: ${DOCKER_COMPOSE_APP_ENV_AI_LLM_API_TPD} + JWT_SECRET: ${JWT_SECRET} TESTING_PLAYWRIGHT_WS_ENDPOINT: "ws://playwright:9323" TESTING_PLAYWRIGHT_BASE_URL: "http://app:4200" @@ -40,8 +41,6 @@ services: - 9876:9876 volumes: - .:/home/node/app - - app_backend_node_modules:/home/node/app/teammapper-backend/node_modules - - app_frontend_node_modules:/home/node/app/teammapper-frontend/node_modules depends_on: - postgres @@ -60,7 +59,7 @@ services: - postgres_data:/var/lib/postgresql/data/pgdata playwright: - image: mcr.microsoft.com/playwright:v1.55.0-noble + image: mcr.microsoft.com/playwright:v1.57.0-noble container_name: playwright depends_on: - app diff --git a/package.json b/package.json index d62dd6168..5af42b06e 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,6 @@ "tsc": "pnpm --filter '*' run tsc" }, "devDependencies": { - "concurrently": "9.1.2" + "concurrently": "9.2.1" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3ddcd951b..a68240c80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,70 +9,76 @@ importers: .: devDependencies: concurrently: - specifier: 9.1.2 - version: 9.1.2 + specifier: 9.2.1 + version: 9.2.1 teammapper-backend: dependencies: '@ai-sdk/openai': - specifier: 2.0.28 - version: 2.0.28(zod@3.25.76) + specifier: 2.0.53 + version: 2.0.53(zod@3.25.76) '@ai-sdk/openai-compatible': - specifier: 1.0.15 - version: 1.0.15(zod@3.25.76) + specifier: 1.0.22 + version: 1.0.22(zod@3.25.76) '@nestjs/cache-manager': - specifier: ^3.0.0 - version: 3.0.1(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(cache-manager@6.4.3)(keyv@5.5.2)(rxjs@7.8.2) + specifier: ^3.0.1 + version: 3.0.1(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(cache-manager@7.2.4)(keyv@5.5.3)(rxjs@7.8.2) '@nestjs/cli': - specifier: ^11.0.7 - version: 11.0.10(@types/node@22.18.6) + specifier: ^11.0.10 + version: 11.0.10(@types/node@24.9.2) '@nestjs/common': - specifier: ^11.1.5 - version: 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: ^11.1.7 + version: 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': specifier: 4.0.2 - version: 4.0.2(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 4.0.2(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': - specifier: ^11.1.5 - version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: ^11.1.7 + version: 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/platform-express': - specifier: ^11.1.5 - version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + specifier: ^11.1.7 + version: 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7) '@nestjs/platform-socket.io': - specifier: ^11.1.5 - version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.6)(rxjs@7.8.2) + specifier: ^11.1.7 + version: 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.7)(rxjs@7.8.2) '@nestjs/schedule': specifier: ^5.0.1 - version: 5.0.1(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + version: 5.0.1(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7) '@nestjs/serve-static': - specifier: ^5.0.3 - version: 5.0.3(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(express@5.1.0) + specifier: ^5.0.4 + version: 5.0.4(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(express@5.1.0) '@nestjs/typeorm': specifier: ^11.0.0 - version: 11.0.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(redis@5.8.2)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3))) + version: 11.0.0(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(redis@5.8.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3))) '@nestjs/websockets': - specifier: ^11.1.5 - version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-socket.io@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: ^11.1.7 + version: 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(@nestjs/platform-socket.io@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@types/uuid': specifier: ^10.0.0 version: 10.0.0 ai: - specifier: 5.0.40 - version: 5.0.40(zod@3.25.76) + specifier: 5.0.80 + version: 5.0.80(zod@3.25.76) cache-manager: - specifier: ^6.4.0 - version: 6.4.3 + specifier: ^7.2.4 + version: 7.2.4 class-validator: - specifier: ^0.14.1 + specifier: ^0.14.2 version: 0.14.2 - dotenv: - specifier: 16.5.0 - version: 16.5.0 + cookie-parser: + specifier: ^1.4.7 + version: 1.4.7 + deepmerge: + specifier: ^4.3.1 + version: 4.3.1 http-proxy-middleware: specifier: 3.0.5 version: 3.0.5 + jsonwebtoken: + specifier: ^9.0.2 + version: 9.0.2 pg: - specifier: ^8.16.0 + specifier: ^8.16.3 version: 8.16.3 pq: specifier: ^0.0.3 @@ -90,93 +96,96 @@ importers: specifier: 4.8.1 version: 4.8.1 typeorm: - specifier: ^0.3.26 - version: 0.3.27(pg@8.16.3)(redis@5.8.2)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + specifier: ^0.3.27 + version: 0.3.27(pg@8.16.3)(redis@5.8.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) uuid: specifier: 11.1.0 version: 11.1.0 devDependencies: '@eslint/compat': - specifier: ^1.3.2 - version: 1.4.0(eslint@9.36.0(jiti@1.21.7)) + specifier: ^1.4.1 + version: 1.4.1(eslint@9.39.0(jiti@1.21.7)) '@eslint/js': - specifier: ^9.34.0 - version: 9.36.0 + specifier: ^9.39.0 + version: 9.39.0 '@golevelup/ts-jest': - specifier: ^0.6.2 - version: 0.6.2 + specifier: ^0.7.0 + version: 0.7.0 '@jest/globals': - specifier: ^30.1.2 - version: 30.1.2 + specifier: ^30.2.0 + version: 30.2.0 '@nestjs/schematics': - specifier: ^11.0.0 - version: 11.0.7(chokidar@4.0.3)(typescript@5.8.3) + specifier: ^11.0.9 + version: 11.0.9(chokidar@4.0.3)(typescript@5.9.3) '@nestjs/testing': - specifier: ^11.1.5 - version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6) + specifier: ^11.1.8 + version: 11.1.8(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(@nestjs/platform-express@11.1.7) '@stylistic/eslint-plugin': - specifier: ^5.2.3 - version: 5.4.0(eslint@9.36.0(jiti@1.21.7)) + specifier: ^5.5.0 + version: 5.5.0(eslint@9.39.0(jiti@1.21.7)) '@types/cache-manager': specifier: 5.0.0 version: 5.0.0 + '@types/cookie-parser': + specifier: ^1.4.10 + version: 1.4.10(@types/express@5.0.5) '@types/cron': specifier: ^2.4.3 version: 2.4.3 '@types/express': - specifier: ^5.0.0 - version: 5.0.3 + specifier: ^5.0.5 + version: 5.0.5 '@types/express-serve-static-core': - specifier: ^5.0.6 - version: 5.0.7 + specifier: ^5.1.0 + version: 5.1.0 '@types/jest': - specifier: 29.5.14 - version: 29.5.14 + specifier: 30.0.0 + version: 30.0.0 + '@types/jsonwebtoken': + specifier: ^9.0.10 + version: 9.0.10 '@types/node': - specifier: ^22.15.30 - version: 22.18.6 + specifier: ^24.9.2 + version: 24.9.2 '@types/supertest': specifier: ^6.0.3 version: 6.0.3 '@typescript-eslint/eslint-plugin': - specifier: ^8.41.0 - version: 8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: ^8.46.2 + version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: ^8.41.0 - version: 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: ^8.46.2 + version: 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) eslint: - specifier: ^9.34.0 - version: 9.36.0(jiti@1.21.7) + specifier: ^9.39.0 + version: 9.39.0(jiti@1.21.7) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.36.0(jiti@1.21.7)) + version: 10.1.8(eslint@9.39.0(jiti@1.21.7)) eslint-import-resolver-typescript: specifier: 4.4.4 - version: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.36.0(jiti@1.21.7)) + version: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.7)) eslint-plugin-import: specifier: 2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@1.21.7)) + version: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.0(jiti@1.21.7)) eslint-plugin-jest: specifier: 29.0.1 - version: 29.0.1(@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3) + version: 29.0.1(@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3) eslint-plugin-nestjs: specifier: 1.2.3 version: 1.2.3 eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.36.0(jiti@1.21.7)))(eslint@9.36.0(jiti@1.21.7))(prettier@3.6.2) + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@1.21.7)))(eslint@9.39.0(jiti@1.21.7))(prettier@3.6.2) eslint-plugin-typeorm: specifier: 0.0.19 version: 0.0.19 globals: - specifier: ^16.2.0 - version: 16.4.0 + specifier: ^16.5.0 + version: 16.5.0 jest: - specifier: 29.7.0 - version: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - jest-jasmine2: - specifier: 29.7.0 - version: 29.7.0 + specifier: 30.2.0 + version: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) prettier: specifier: ^3.6.2 version: 3.6.2 @@ -184,71 +193,71 @@ importers: specifier: ^4.8.1 version: 4.8.1 supertest: - specifier: ^7.1.1 + specifier: ^7.1.4 version: 7.1.4 ts-jest: - specifier: 29.4.0 - version: 29.4.0(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@30.0.5)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3) + specifier: 29.4.5 + version: 29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.25.11)(jest-util@30.2.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3) ts-loader: - specifier: ^9.5.2 - version: 9.5.4(typescript@5.8.3)(webpack@5.101.2) + specifier: ^9.5.4 + version: 9.5.4(typescript@5.9.3)(webpack@5.101.2) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@22.18.6)(typescript@5.8.3) + version: 10.9.2(@types/node@24.9.2)(typescript@5.9.3) tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 typescript: - specifier: ~5.8.2 - version: 5.8.3 + specifier: ~5.9.3 + version: 5.9.3 typescript-eslint: - specifier: ^8.41.0 - version: 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: ^8.46.2 + version: 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) teammapper-frontend: dependencies: '@angular-devkit/build-angular': - specifier: 20.3.2 - version: 20.3.2(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@22.18.6)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.9.2)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(jiti@1.21.7)(typescript@5.9.3) '@angular/animations': - specifier: 20.3.1 - version: 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + specifier: 20.3.7 + version: 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@angular/cdk': - specifier: 20.0.2 - version: 20.0.2(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + specifier: 20.2.10 + version: 20.2.10(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) '@angular/cli': - specifier: 20.3.2 - version: 20.3.2(@types/node@22.18.6)(chokidar@4.0.3) + specifier: 20.3.7 + version: 20.3.7(@types/node@24.9.2)(chokidar@4.0.3) '@angular/common': - specifier: 20.3.1 - version: 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) '@angular/compiler': - specifier: 20.3.1 - version: 20.3.1 + specifier: 20.3.7 + version: 20.3.7 '@angular/compiler-cli': - specifier: 20.3.1 - version: 20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3) '@angular/core': - specifier: 20.3.1 - version: 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) + specifier: 20.3.7 + version: 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) '@angular/forms': - specifier: 20.3.1 - version: 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@angular/material': - specifier: 20.0.2 - version: 20.0.2(2bbdcc961587c2d21a1f5fd45a68ee52) + specifier: 20.2.10 + version: 20.2.10(72d1932aa29c0670c8359e3ed8a5ff55) '@angular/platform-browser': - specifier: 20.3.1 - version: 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + specifier: 20.3.7 + version: 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@angular/platform-browser-dynamic': - specifier: 20.3.1 - version: 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))) '@angular/router': - specifier: 20.3.1 - version: 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + specifier: 20.3.7 + version: 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@fortawesome/angular-fontawesome': specifier: ^2.0.1 - version: 2.0.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + version: 2.0.1(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@fortawesome/fontawesome-svg-core': specifier: ^6.7.2 version: 6.7.2 @@ -259,50 +268,50 @@ importers: specifier: ^6.7.2 version: 6.7.2 '@material-design-icons/font': - specifier: ^0.14.13 + specifier: ^0.14.15 version: 0.14.15 '@ngx-translate/core': - specifier: ^16.0.3 - version: 16.0.4(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + specifier: ^16.0.4 + version: 16.0.4(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@ngx-translate/http-loader': specifier: ^16.0.1 - version: 16.0.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + version: 16.0.1(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) '@teammapper/mermaid-mindmap-parser': - specifier: workspace:^0.0.1 + specifier: workspace:^ version: link:packages/mermaid-mindmap-parser '@types/uuid': specifier: ^10.0.0 version: 10.0.0 ai: - specifier: ^5.0.40 - version: 5.0.40(zod@3.25.76) + specifier: ^5.0.80 + version: 5.0.80(zod@3.25.76) angular2-hotkeys: specifier: ^16.0.1 version: 16.0.1 d3: - specifier: 7.6.1 - version: 7.6.1 + specifier: 7.9.0 + version: 7.9.0 deep-object-diff: specifier: ^1.1.9 version: 1.1.9 dompurify: - specifier: 3.2.4 - version: 3.2.4 + specifier: 3.3.0 + version: 3.3.0 jspdf: - specifier: ^3.0.2 + specifier: ^3.0.3 version: 3.0.3 localforage: specifier: 1.10.0 version: 1.10.0 ngx-color-picker: specifier: ^17.0.0 - version: 17.0.0(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)) + version: 17.0.0(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)) ngx-toastr: - specifier: ^19.0.0 - version: 19.1.0(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))) + specifier: ^19.1.0 + version: 19.1.0(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))) qr-code-styling: - specifier: 1.9.1 - version: 1.9.1 + specifier: 1.9.2 + version: 1.9.2 rxjs: specifier: ~7.8.2 version: 7.8.2 @@ -321,116 +330,113 @@ importers: devDependencies: '@angular-builders/jest': specifier: ^20.0.0 - version: 20.0.0(6c01f59db48b8ca6db50360b9422a4c0) + version: 20.0.0(298286e299ccfff78b1834faa98544c9) '@angular-devkit/architect': - specifier: 0.2003.2 - version: 0.2003.2(chokidar@4.0.3) + specifier: 0.2003.8 + version: 0.2003.8(chokidar@4.0.3) '@angular-devkit/core': - specifier: 20.3.2 - version: 20.3.2(chokidar@4.0.3) + specifier: 20.3.8 + version: 20.3.8(chokidar@4.0.3) '@angular-devkit/schematics': - specifier: 20.3.2 - version: 20.3.2(chokidar@4.0.3) + specifier: 20.3.8 + version: 20.3.8(chokidar@4.0.3) '@angular-eslint/builder': - specifier: 20.2.0 - version: 20.2.0(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: 20.5.0 + version: 20.5.0(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) '@angular-eslint/eslint-plugin': - specifier: 20.2.0 - version: 20.2.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: 20.5.0 + version: 20.5.0(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) '@angular-eslint/eslint-plugin-template': - specifier: 20.2.0 - version: 20.2.0(@angular-eslint/template-parser@20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: 20.5.0 + version: 20.5.0(@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/types@8.46.2)(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) '@angular-eslint/schematics': - specifier: 20.2.0 - version: 20.2.0(@angular-eslint/template-parser@20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: 20.5.0 + version: 20.5.0(@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/types@8.46.2)(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) '@angular-eslint/template-parser': - specifier: 20.2.0 - version: 20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: 20.5.0 + version: 20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) '@angular/language-service': - specifier: 20.3.1 - version: 20.3.1 + specifier: 20.3.9 + version: 20.3.9 '@compodoc/compodoc': - specifier: ^1.1.26 - version: 1.1.30(typescript@5.8.3) + specifier: ^1.1.32 + version: 1.1.32(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)(keycharm@0.2.0)(typescript@5.9.3)(vis-data@8.0.3(uuid@11.1.0)(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)))(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)) '@eslint/js': - specifier: ^9.34.0 - version: 9.36.0 + specifier: ^9.39.0 + version: 9.39.0 '@playwright/test': - specifier: ^1.55.0 - version: 1.55.1 + specifier: ^1.57.0 + version: 1.57.0 '@schematics/angular': - specifier: ^19.2.12 - version: 19.2.17(chokidar@4.0.3) + specifier: ^20.3.8 + version: 20.3.8(chokidar@4.0.3) '@types/d3': - specifier: 7.1.0 - version: 7.1.0 - '@types/jasmine': - specifier: ~5.1.4 - version: 5.1.9 + specifier: 7.4.3 + version: 7.4.3 '@types/jest': - specifier: 29.5.14 - version: 29.5.14 + specifier: 30.0.0 + version: 30.0.0 '@types/mousetrap': specifier: 1.6.15 version: 1.6.15 '@types/node': - specifier: ^22.15.19 - version: 22.18.6 + specifier: ^24.9.2 + version: 24.9.2 '@typescript-eslint/eslint-plugin': - specifier: ^8.41.0 - version: 8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: ^8.46.2 + version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) '@typescript-eslint/parser': - specifier: ^8.41.0 - version: 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: ^8.46.2 + version: 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) angular-eslint: - specifier: ^20.2.0 - version: 20.3.0(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript-eslint@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(typescript@5.8.3) + specifier: ^20.5.0 + version: 20.5.0(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript-eslint@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(typescript@5.9.3) eslint: - specifier: ^9.34.0 - version: 9.36.0(jiti@1.21.7) + specifier: ^9.39.0 + version: 9.39.0(jiti@1.21.7) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.36.0(jiti@1.21.7)) + version: 10.1.8(eslint@9.39.0(jiti@1.21.7)) eslint-plugin-jest: specifier: ^29.0.1 - version: 29.0.1(@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3) + version: 29.0.1(@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.36.0(jiti@1.21.7)))(eslint@9.36.0(jiti@1.21.7))(prettier@3.6.2) + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@1.21.7)))(eslint@9.39.0(jiti@1.21.7))(prettier@3.6.2) globals: - specifier: ^15.11.0 - version: 15.15.0 + specifier: ^16.5.0 + version: 16.5.0 jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + specifier: ^30.2.0 + version: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) jest-canvas-mock: specifier: ^2.5.2 version: 2.5.2 jest-preset-angular: - specifier: ^14.6.0 - version: 14.6.1(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(jsdom@20.0.3)(typescript@5.8.3) + specifier: ^15.0.3 + version: 15.0.3(e802ad861324f03ef4b0eb9da0770013) minimist: - specifier: ^1.2.5 + specifier: ^1.2.8 version: 1.2.8 prettier: - specifier: ^3.3.3 + specifier: ^3.6.2 version: 3.6.2 ts-node: specifier: ~10.9.2 - version: 10.9.2(@types/node@22.18.6)(typescript@5.8.3) + version: 10.9.2(@types/node@24.9.2)(typescript@5.9.3) typescript: - specifier: ~5.8.3 - version: 5.8.3 + specifier: ~5.9.3 + version: 5.9.3 typescript-eslint: - specifier: ^8.41.0 - version: 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + specifier: ^8.46.2 + version: 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) optionalDependencies: '@nx/nx-darwin-arm64': specifier: 21.2.0 version: 21.2.0 '@nx/nx-darwin-x64': - specifier: 20.0.3 - version: 20.0.3 + specifier: 21.6.5 + version: 21.6.5 '@nx/nx-linux-x64-gnu': specifier: 19.8.2 version: 19.8.2 @@ -441,47 +447,47 @@ importers: teammapper-frontend/packages/mermaid-mindmap-parser: dependencies: dompurify: - specifier: 3.2.4 - version: 3.2.4 + specifier: 3.3.0 + version: 3.3.0 devDependencies: jison: specifier: 0.4.18 version: 0.4.18 typescript: - specifier: ~5.8.3 - version: 5.8.3 + specifier: ~5.9.3 + version: 5.9.3 vite: - specifier: ^6.3.5 - version: 6.3.6(@types/node@22.18.6)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.44.0) + specifier: ^7.1.12 + version: 7.1.12(@types/node@24.9.2)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.44.0) packages: '@aduh95/viz.js@3.4.0': resolution: {integrity: sha512-KI2nVf9JdwWCXqK6RVf+9/096G7VWN4Z84mnynlyZKao2xQENW8WNEjLmvdlxS5X8PNWXFC1zqwm7tveOXw/4A==} - '@ai-sdk/gateway@1.0.21': - resolution: {integrity: sha512-yQPrMb1v0P8GwmmpcCT2DGPfgJVRkJ9QaRRJGO0+Em+wI+Xv3lvHHIc3ImVR3jjVfJPih/cNWWALUgRERfQaxQ==} + '@ai-sdk/gateway@2.0.1': + resolution: {integrity: sha512-vPVIbnP35ZnayS937XLo85vynR85fpBQWHCdUweq7apzqFOTU2YkUd4V3msebEHbQ2Zro60ZShDDy9SMiyWTqA==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 || ^4 + zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai-compatible@1.0.15': - resolution: {integrity: sha512-i4TzohCxuFzBSdRNPa9eNFW6AYDZ5itbxz+rJa2kpNTMYqHgqKPGzet3X6eLIUVntA10icrqhWT+hUhxXZIS9Q==} + '@ai-sdk/openai-compatible@1.0.22': + resolution: {integrity: sha512-Q+lwBIeMprc/iM+vg1yGjvzRrp74l316wDpqWdbmd4VXXlllblzGsUgBLTeKvcEapFTgqk0FRETvSb58Y6dsfA==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 || ^4 + zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@2.0.28': - resolution: {integrity: sha512-Z2mG7PjUKbpT8fMexE6yrorxXVzGHSl3jKF293w2i6s9Dc6X81Gf6Z0OGNnkrftLtW4PXr7RZ/9xoyusBZW4uA==} + '@ai-sdk/openai@2.0.53': + resolution: {integrity: sha512-GIkR3+Fyif516ftXv+YPSPstnAHhcZxNoR2s8uSHhQ1yBT7I7aQYTVwpjAuYoT3GR+TeP50q7onj2/nDRbT2FQ==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 || ^4 + zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@3.0.8': - resolution: {integrity: sha512-cDj1iigu7MW2tgAQeBzOiLhjHOUM9vENsgh4oAVitek0d//WdgfPCsKO3euP7m7LyO/j9a1vr/So+BGNdpFXYw==} + '@ai-sdk/provider-utils@3.0.12': + resolution: {integrity: sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 || ^4 + zod: ^3.25.76 || ^4.1.8 '@ai-sdk/provider@2.0.0': resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} @@ -561,12 +567,16 @@ packages: '@angular/platform-browser-dynamic': ^20.0.0 jest: '>=29' - '@angular-devkit/architect@0.2003.2': - resolution: {integrity: sha512-3QFQlSg92lz+Zid1CGcnYVuPo0RIyq+TEbaJUQmi7K9Ms0VxVNMIwTNIN3SI6QThD0Bg3sVRtsHWw84qoMwjKA==} + '@angular-devkit/architect@0.2003.7': + resolution: {integrity: sha512-NGHLfrNQNjwWwvyQomMM1AqRaqH3UU0TwySJh9XlSc9dC/roB5zD2NjLf98K4LfAIfHvDBwkQ+dMo3F556/Xuw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/build-angular@20.3.2': - resolution: {integrity: sha512-DMNyW17Z4a7zyew9YJrNcNnKSbgFBc+EsFSa05dH5oLvcwtGQood35AzhncXpsUqO16NQBfWuUscuf2WrvG1iA==} + '@angular-devkit/architect@0.2003.8': + resolution: {integrity: sha512-pbXQ2NlZQwzjsSIEoRQMGB1WrgZFCyM0zoD9h+rDjyR8PEB1Evl4evZ4Q5CJzjEBxC8IEG61PHKHjh8GdLb+sg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + + '@angular-devkit/build-angular@20.3.7': + resolution: {integrity: sha512-KVA6ztqrZz/DKSCk/iV9fz9Af+54YyZs25KwClBi+7/RJIBNml8CZQLW51VxIkbjD9aZdVZdUMkkbQJp5MgY5w==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: '@angular/compiler-cli': ^20.0.0 @@ -575,7 +585,7 @@ packages: '@angular/platform-browser': ^20.0.0 '@angular/platform-server': ^20.0.0 '@angular/service-worker': ^20.0.0 - '@angular/ssr': ^20.3.2 + '@angular/ssr': ^20.3.7 '@web/test-runner': ^0.20.0 browser-sync: ^3.0.2 jest: ^29.5.0 @@ -615,8 +625,8 @@ packages: tailwindcss: optional: true - '@angular-devkit/build-webpack@0.2003.2': - resolution: {integrity: sha512-cipoxofI4HdKk9lAqPloPrp/HEV3ME3fIKSmckUsmPcJzy62YdXkkFv6zE4EENUPNP5d8SoSpZ5FPW+wNMV+yg==} + '@angular-devkit/build-webpack@0.2003.7': + resolution: {integrity: sha512-9CVEUWOzf7sk6eudFEG3pfDT1AScUJ4+ekRFKyD5Q5sZivMjjVFqwQp7YUpHpZusZX6sgpT+Crj5Ydva+I/dvw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: webpack: ^5.30.0 @@ -640,8 +650,17 @@ packages: chokidar: optional: true - '@angular-devkit/core@20.2.2': - resolution: {integrity: sha512-SC+f5isSWJBpEgR+R7jP++2Z14WExNWLAdKpIickLWjuL8FlGkj+kaF3dWXhh0KcXo+r6kKb4pWUptSaqer5gA==} + '@angular-devkit/core@20.3.4': + resolution: {integrity: sha512-r83jn9yVdPh618oGgoKPggMsQGOkQqJbxEutd4CE9mnotPCE2uRTIyaFMh8sohNUeoQNRmj9rbr2pWGVlgERpg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^4.0.0 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular-devkit/core@20.3.7': + resolution: {integrity: sha512-psmcjwYcXve4sLrcdnARc15/Wfd3RpydbtLo9+mViNzk5HQ6L2eEztKl/2QVYMgzZVIa1GfhjwUllVCyLAv3sg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: chokidar: ^4.0.0 @@ -649,8 +668,8 @@ packages: chokidar: optional: true - '@angular-devkit/core@20.3.2': - resolution: {integrity: sha512-MsYPu/WaHQInCxLRfX3vOaf4uedvwX5yI29X/tQpD59/gI5Yq4YMDT48ntryZHclRuQ9x4vdm2Gp9e/LcP0ydw==} + '@angular-devkit/core@20.3.8': + resolution: {integrity: sha512-+YFpJdvlL4gxnMm/++8rseE7ZNRHlYPmOqpoiXSuP5eGPSmdklEoQGTQvpMw42S3bll1g6/029DmV2FCZ/dtEQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: chokidar: ^4.0.0 @@ -671,104 +690,67 @@ packages: resolution: {integrity: sha512-ADfbaBsrG8mBF6Mfs+crKA/2ykB8AJI50Cv9tKmZfwcUcyAdmTr+vVvhsBCfvUAEokigSsgqgpYxfkJVxhJYeg==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/schematics@20.2.2': - resolution: {integrity: sha512-rtL7slZjzdChQoiADKZv/Ra8D3C3tIw/WcVxd2stiLHdK/Oaf9ejx5m/X9o0QMEbNsy2Fy/RKodNqmz1CjzpCg==} + '@angular-devkit/schematics@20.3.4': + resolution: {integrity: sha512-JYlcmVBKNT9+cQ6T2tmu+yVQ2bJk8tG0mXvPHWXrl/M4c6NObhSSThK50tJHy0Xo3gl8WgogOxUeJNnBq67cIQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-devkit/schematics@20.3.2': - resolution: {integrity: sha512-CHHq2qWgHNi3fkhBMpSxVSrST2mBN31QfZpvKFp1sWvtJDN7sRHlvLCML81+KplVd8aWkbQqeAG73dgRDPbSBw==} + '@angular-devkit/schematics@20.3.7': + resolution: {integrity: sha512-DUxcQBPKO69p56ZgIdVfxWyLiSjdcUoD6BH9/nWHp0QiqRAR6GcXP4SFax76JPl2WsiCp4hHZ233Hf69AP1xew==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-eslint/builder@20.2.0': - resolution: {integrity: sha512-0qej+U/u5MDnvnUhrWAXmXJd7ZliZzYQtkmy50ypq/LaQwkOuZBEFh9EqlZ1k4n8n2DKQou03KJmKSoAqc/I8A==} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' + '@angular-devkit/schematics@20.3.8': + resolution: {integrity: sha512-Ymv7nWLTDB1gBh2laRveO912eUpQ/rUIzKRr8VQFMVG/wNipL88vzyrlKhJa7WhQ3CdKxLD7kplFIjdev7XUVg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@angular-eslint/builder@20.3.0': - resolution: {integrity: sha512-3XpWLdh+/K4+r0ChkKW00SXWyBA7ShMpE+Pt1XUmIu4srJgGRnt8e+kC4Syi+s2t5QS7PjlwRaelB1KfSMXZ5A==} + '@angular-eslint/builder@20.5.0': + resolution: {integrity: sha512-ycrvgomFgitSwzDndo+i3Ob1iu9lAJeuZZ8cwBR4E/RYsCxNm02NLCv5qjQ3ya57yjkh12N6yvjzWnCO9Vdiuw==} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '*' - '@angular-eslint/bundled-angular-compiler@20.2.0': - resolution: {integrity: sha512-9NhytRavpxWqa0fK+mlQZrif91MhtG3VEV3JCQEwOH9JPueY95XVHYwPgcbODhoSg/z5YaTVby5G254cEXUMew==} - - '@angular-eslint/bundled-angular-compiler@20.3.0': - resolution: {integrity: sha512-QwuNnmRNr/uNj89TxknPbGcs5snX1w7RoJJPNAsfb2QGcHzUTQovS8hqm9kaDZdpUJDPP7jt7B6F0+EjrPAXRA==} + '@angular-eslint/bundled-angular-compiler@20.5.0': + resolution: {integrity: sha512-XjvSZk+G/4rRUOLHHjlHBeS4OnnsLV9G1YtE5OerBB2H4x6nKgUEzpptad3uuL4iYWI9rGaWMLqGPTvyYqw/IA==} - '@angular-eslint/eslint-plugin-template@20.2.0': - resolution: {integrity: sha512-pRuROa9QUUIq/ulB5rbXrwOhFA1tcR8HhGq187gFQfPno/bFZfbF9R8x+zukbVipNjl087WHUWj09KNDcJBLlA==} + '@angular-eslint/eslint-plugin-template@20.5.0': + resolution: {integrity: sha512-sX3TgTTGusYv4CjnEWWNvSyVCPmf2WF2LT5NpcKF+4BLcIVLXHdTXKz9H+OxIHeHk9R7QSRkuop/F7DAKyEPhA==} peerDependencies: - '@angular-eslint/template-parser': 20.2.0 + '@angular-eslint/template-parser': 20.5.0 '@typescript-eslint/types': ^7.11.0 || ^8.0.0 '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 eslint: ^8.57.0 || ^9.0.0 typescript: '*' - '@angular-eslint/eslint-plugin-template@20.3.0': - resolution: {integrity: sha512-WMJDJfybOLCiN4QrOyrLl+Zt5F+A/xoDYMWTdn+LgACheLs2tguVQiwf+oCgHnHGcsTsulPYlRHldKBGZMgs4w==} + '@angular-eslint/eslint-plugin@20.5.0': + resolution: {integrity: sha512-xpBrx4qCq0mzQ1lmqHa06faxHuKvBZGYb5owP/vTQBr2kZvQ502ENp5vwv+NS04TRKcWht1zHbMfy9rKRdhL5w==} peerDependencies: - '@angular-eslint/template-parser': 20.3.0 - '@typescript-eslint/types': ^7.11.0 || ^8.0.0 '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 eslint: ^8.57.0 || ^9.0.0 typescript: '*' - '@angular-eslint/eslint-plugin@20.2.0': - resolution: {integrity: sha512-HdujUz7Q1ZW371cCJRkUcp0bjU/iP8Z/ZNTStCzMd4euu+HwVt69dLsTCs6f1i6SMqlIUjaP8TbqNo5nV8Altw==} - peerDependencies: - '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' + '@angular-eslint/schematics@20.5.0': + resolution: {integrity: sha512-pYGxMKocgUzKIMOOYBcGjvtxRcvnOY5ETs64IFcdHnwKoFfWeQV0a77sJdDj1YGOu/mj4PeORTRHfQyLvbhvyQ==} - '@angular-eslint/eslint-plugin@20.3.0': - resolution: {integrity: sha512-7ghzGTiExrgTetDQ6IPP5uXSa94Xhtzp2VHCIa58EcUb7oMv06HWZ1Uss3xgFmACsLpN+vayKJIdFiboqaGVRA==} + '@angular-eslint/template-parser@20.5.0': + resolution: {integrity: sha512-dWaz2Knjy6yJI5/xVYqp5iu65b725wveMwt1DgJ9EDTZ5gpJcTsvSCW4zQr/6iXfpAZHKPh9LJvVW1svowhtWw==} peerDependencies: - '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 eslint: ^8.57.0 || ^9.0.0 typescript: '*' - '@angular-eslint/schematics@20.2.0': - resolution: {integrity: sha512-vAslYgJ2Rs2xY80ckwbuv/YWpEO9d/lFMq8CGrm37PI0IB5uRuGVWxaVboBLP6WUj9iMS/ufZUcCu0fdQ05V8Q==} - - '@angular-eslint/schematics@20.3.0': - resolution: {integrity: sha512-4n92tHKIJm1PP+FjhnmO7AMpvKdRIoF+YgF38oUU7aMJqfZ3RXIhazMMxw2u3VU1MisKH766KSll++c4LgarVA==} - - '@angular-eslint/template-parser@20.2.0': - resolution: {integrity: sha512-72hskYThlVhktpRCwSwAohY/SxUoMv0hhS71zjlJcHFTzTAWCI8Zy2U4OJuhUO7+XWL6iAu13NKzJKRzUhGdSw==} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - - '@angular-eslint/template-parser@20.3.0': - resolution: {integrity: sha512-gB564h/kZ7siWvgHDETU++sk5e25qFfVaizLaa6KoBEYFP6dOCiedz15LTcA0TsXp0rGu6Z6zkl291iSM1qzDA==} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - - '@angular-eslint/utils@20.2.0': - resolution: {integrity: sha512-GnEa8BU9xBLUq4JQ8UgXecUXPCmju9P5KIobql17LV1t3vnJ33Zr7acO1jWOzluypllKSVrtARdRTI+TQGCqrA==} - peerDependencies: - '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - - '@angular-eslint/utils@20.3.0': - resolution: {integrity: sha512-7XOQeNXgyhznDwoP1TwPrCMq/uXKJHQgCVPFREkJGKbNf/jzNldB7iV1eqpBzUQIPEQFgfcDG67dexpMAq3N4g==} + '@angular-eslint/utils@20.5.0': + resolution: {integrity: sha512-eP8al/UKP9FpmwK3hVWkYUjBuq4BnUDrcboS51L9mRZsoOblkPt1/UgU6MJqW8sh6sfebP9N3RxLQOAFrM3juQ==} peerDependencies: '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 eslint: ^8.57.0 || ^9.0.0 typescript: '*' - '@angular/animations@20.3.1': - resolution: {integrity: sha512-mexSwaikVE2s+GDhB9fuagEvxbnKHWsqLlO7/R2nY9tTUxBO3drWe3p0D5GxG/EsEyzZU+86ED867q/JmAiVvw==} + '@angular/animations@20.3.7': + resolution: {integrity: sha512-i655RaL0zmLE3OESUlDnRNBDRIMW/67nTQvMqP6V1cQ42l2+SMJtREsxmX6cWt55/qvvgeytAA6aBN4aerBl5A==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/core': 20.3.1 + '@angular/core': 20.3.7 - '@angular/build@20.3.2': - resolution: {integrity: sha512-PiyvOvNtNM9p2YdCgNHTCqF7Fnyq5ug45Zhv7m6yRgin5VcDuSF/Mv2x7AY3HiN+w89Oxozvm13cSanzrw7acA==} + '@angular/build@20.3.7': + resolution: {integrity: sha512-NHN5JNDqUc0Ux4IZPCe/fpFAnuRHujkxVfRHSqDFW5+jtj2JuW1XO6qlX+kDheFRlj/NvFgTpidKsE9IjpfMWQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: '@angular/compiler': ^20.0.0 @@ -778,7 +760,7 @@ packages: '@angular/platform-browser': ^20.0.0 '@angular/platform-server': ^20.0.0 '@angular/service-worker': ^20.0.0 - '@angular/ssr': ^20.3.2 + '@angular/ssr': ^20.3.7 karma: ^6.4.0 less: ^4.2.0 ng-packagr: ^20.0.0 @@ -813,45 +795,45 @@ packages: vitest: optional: true - '@angular/cdk@20.0.2': - resolution: {integrity: sha512-gRQcpTNhnwBxXSmpnrljODUHQmB2Hnxc6L2Ad6mSMV+c3opd9KIFxL5eG2WOOPHGAaPrV4gNFw+t1i01U4grTg==} + '@angular/cdk@20.2.10': + resolution: {integrity: sha512-d95C2r3JP11KCahouWmPaxswz/EE7Zn1k8ocoGt70jl33x42Sg96vAHeOpnQ4yfrdA4W7Q+eWB/NqqvAGCzOPQ==} peerDependencies: '@angular/common': ^20.0.0 || ^21.0.0 '@angular/core': ^20.0.0 || ^21.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/cli@20.3.2': - resolution: {integrity: sha512-5R+f11IbGkNGXTwTfVbhQXCh/jdQxlmdK11P3yoqhj2OcBM+GY8ALCyf0vyoOxocxt7NAJUq4fIpT9W2YhTVLQ==} + '@angular/cli@20.3.7': + resolution: {integrity: sha512-hNurF7g/e9cDHFBRCKLPSmQJs0n28jZsC3sTl/XuWE8PYtv5egh2EuqrxdruYB5GdANpIqSQNgDGQJrKrk/XnQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} hasBin: true - '@angular/common@20.3.1': - resolution: {integrity: sha512-7Ru3BO4MOBQRMu9GJS+061cUsevKNsNAMxXnQtcqEaNyntUg2v0XiMdv4I7pQGtkQjFK17bKAxQ97jqxJfqsRQ==} + '@angular/common@20.3.7': + resolution: {integrity: sha512-uf8dXYTJbedk/wudkt2MfbtvN/T97aEZBtOTq8/IFQQZ3722rag6D+Cg76e5hBccROOn+ueGJX2gpxz02phTwA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/core': 20.3.1 + '@angular/core': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 - '@angular/compiler-cli@20.3.1': - resolution: {integrity: sha512-aFfGHi/ApYxmvF4cCS0TypcviQ/Xy+0fwTTrLC8znPC1vObBn0DUA0I6D5dP+xlOTx8PFLkgndNYa2f6RIluvg==} + '@angular/compiler-cli@20.3.7': + resolution: {integrity: sha512-viZwWlwc1BAqryRJE0Wq2WgAxDaW9fuwtYHYrOWnIn9sy9KemKmR6RmU9VRydrwUROOlqK49R9+RC1wQ6sYwqA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true peerDependencies: - '@angular/compiler': 20.3.1 + '@angular/compiler': 20.3.7 typescript: '>=5.8 <6.0' peerDependenciesMeta: typescript: optional: true - '@angular/compiler@20.3.1': - resolution: {integrity: sha512-zRYAdAG/hsJegXapKxElLU6Q5in8UG9Pbxyh90k89qsZwkuv+CfxVY5OBS2xjk1azt808++yhjfvbO/Em+HMKg==} + '@angular/compiler@20.3.7': + resolution: {integrity: sha512-EouHO15dUsgnFArj0M25R8cOPVoUfiFYSt6iXnMO8+S4dY1fDEmbFqkW5smlP66HL5Gys59Nwb5inejfIWHrLw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@angular/core@20.3.1': - resolution: {integrity: sha512-O03k9ivZ2CvoHXiXGH5WKlWlTtxF2UGMwGXWnV54vGViHwNcvU5Z3h6Ve6mdU9dYMHK9sGljYZnkRpwI3B8mnQ==} + '@angular/core@20.3.7': + resolution: {integrity: sha512-2UuYzC2A5SUtu33tYTN411Wk0WilA+2Uld/GP3O6mragw1O7v/M8pMFmbe9TR5Ah/abRJIocWGlNqeztZmQmrw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/compiler': 20.3.1 + '@angular/compiler': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 zone.js: ~0.15.0 peerDependenciesMeta: @@ -860,56 +842,56 @@ packages: zone.js: optional: true - '@angular/forms@20.3.1': - resolution: {integrity: sha512-P7cmfK1ldXS8KuPTwwIUTZs5AxhbPNumlumq+nfNJZAxv8/PQJh2W729M/EKHG8rB8cXjoo1K+olExnJNPVDTw==} + '@angular/forms@20.3.7': + resolution: {integrity: sha512-uOCGCoqXeAWIlQMWiIeed/W8g8h2tk91YemMI+Ce1VQ/36Xfft40Bouz4eKcvJV6kLXGygdpWjzFGz32CE+3Og==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 20.3.1 - '@angular/core': 20.3.1 - '@angular/platform-browser': 20.3.1 + '@angular/common': 20.3.7 + '@angular/core': 20.3.7 + '@angular/platform-browser': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 - '@angular/language-service@20.3.1': - resolution: {integrity: sha512-tvQXQ5LHaI+iI+rXWshDKyvVmFVz3YxMQvD3kGBNvDlC4+6aCbM4aKii64TafpVkbRUwrmNj1wtAkgHbu9CCjA==} + '@angular/language-service@20.3.9': + resolution: {integrity: sha512-aCsuzlFx8a/VMBNgXMfwai97j2QHZ8PhQwzwodDNb2X3eQsaUO+nCgs5kNIZmQ/rJESH+fY9ZdlZcrYbVp+nBA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@angular/material@20.0.2': - resolution: {integrity: sha512-yIXvF+LjFdHjJWyvn1SxbWB9LdNxYnqEKbKzminW4WPXlPJMOAeyhEDFeQv9W92Zv+/ibS4tI3/SD759ejb45g==} + '@angular/material@20.2.10': + resolution: {integrity: sha512-WkJfUu7KiQY2lqHjMZtEKBG653sPmky0nytTMASsfQ/xUs56W3CAAEOuKhSyCNKsNeFJZS/NgJnvlpRzcE5k6g==} peerDependencies: - '@angular/cdk': 20.0.2 + '@angular/cdk': 20.2.10 '@angular/common': ^20.0.0 || ^21.0.0 '@angular/core': ^20.0.0 || ^21.0.0 '@angular/forms': ^20.0.0 || ^21.0.0 '@angular/platform-browser': ^20.0.0 || ^21.0.0 rxjs: ^6.5.3 || ^7.4.0 - '@angular/platform-browser-dynamic@20.3.1': - resolution: {integrity: sha512-7/u+nI4iAi6YhMVlyn3kTUIeuDbS8JNUo+UNxH++jv51v6ppbpsYu+O18b5PRBaIa9jugIe9lpypH1nctO3mXg==} + '@angular/platform-browser-dynamic@20.3.7': + resolution: {integrity: sha512-4TEPA12183cMeVCzuU/Rmuk5RuIgsunTbjgx0o+ymxvYyULOxKDlhZ4hGDKzmRCOu6s3ZeEs4XbgaLP6pK+Kxg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 20.3.1 - '@angular/compiler': 20.3.1 - '@angular/core': 20.3.1 - '@angular/platform-browser': 20.3.1 + '@angular/common': 20.3.7 + '@angular/compiler': 20.3.7 + '@angular/core': 20.3.7 + '@angular/platform-browser': 20.3.7 - '@angular/platform-browser@20.3.1': - resolution: {integrity: sha512-JiQWRvyVZDH0N9p+pnMOuTFGaw7jPakWDQCJBOBBLdE6AyOiy8YPBImRMrjNNIEqg36h1a8H32rBorf2TL3ExA==} + '@angular/platform-browser@20.3.7': + resolution: {integrity: sha512-AbLtyR7fVEGDYyrz95dP2pc69J5XIjLLsFNAuNQPzNX02WPoAxtrWrNY6UnTzGoSrCc5F52hiL2Uo6yPZTiJcg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/animations': 20.3.1 - '@angular/common': 20.3.1 - '@angular/core': 20.3.1 + '@angular/animations': 20.3.7 + '@angular/common': 20.3.7 + '@angular/core': 20.3.7 peerDependenciesMeta: '@angular/animations': optional: true - '@angular/router@20.3.1': - resolution: {integrity: sha512-lwXKuGe546Pu8vw9M5TolS1EHX69dRfOnCmBOpvGVRqzDNwVT7jfIFcSn++WPs7jhi6T6RPdcVCnIbeO0IRJYQ==} + '@angular/router@20.3.7': + resolution: {integrity: sha512-Lq7mCNcLP1npmNh2JlNEe02YS2jNnaLnCy/t//o+Qq0c6DGV78JRl7pHubiB2R6XXlgvOcZWg88v94Li+y85Iw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@angular/common': 20.3.1 - '@angular/core': 20.3.1 - '@angular/platform-browser': 20.3.1 + '@angular/common': 20.3.7 + '@angular/core': 20.3.7 + '@angular/platform-browser': 20.3.7 rxjs: ^6.5.3 || ^7.4.0 '@arr/every@1.0.1': @@ -920,8 +902,8 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} '@babel/core@7.28.3': @@ -932,10 +914,18 @@ packages: resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} engines: {node: '>=6.9.0'} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.28.3': resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -944,14 +934,14 @@ packages: resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.27.1': - resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -965,8 +955,8 @@ packages: resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.27.1': @@ -1015,6 +1005,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -1027,13 +1021,13 @@ packages: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': - resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1195,8 +1189,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.4': - resolution: {integrity: sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==} + '@babel/plugin-transform-block-scoping@7.28.5': + resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1225,8 +1219,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1261,8 +1255,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.27.1': - resolution: {integrity: sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==} + '@babel/plugin-transform-exponentiation-operator@7.28.5': + resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1297,8 +1291,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.27.1': - resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} + '@babel/plugin-transform-logical-assignment-operators@7.28.5': + resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1321,8 +1315,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.27.1': - resolution: {integrity: sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==} + '@babel/plugin-transform-modules-systemjs@7.28.5': + resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1375,8 +1369,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.27.1': - resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} + '@babel/plugin-transform-optional-chaining@7.28.5': + resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1506,26 +1500,33 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} '@babel/types@7.28.4': resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + '@cacheable/utils@2.1.0': + resolution: {integrity: sha512-ZdxfOiaarMqMj+H7qwlt5EBKWaeGihSYVHdQv5lUsbn8MJJOTW82OIwirQ39U5tMZkNvy3bQE+ryzC+xTAb9/g==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - '@compodoc/compodoc@1.1.30': - resolution: {integrity: sha512-pdFe1tnskXmvj8lfXZgq7LwgAxAPYfxflcGZiexMu1fOyRVsZYrBcHHEWp0sX9FU+or61IOicJv8Vdcri08FEQ==} + '@compodoc/compodoc@1.1.32': + resolution: {integrity: sha512-kaYk5+o4k7GB585iphwV5NE49BKKk8d+gJLNBE8eu2fIRdhnHOWblasRbOBRULfwJ+qxfmgrIqi32K34wCag6A==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} hasBin: true @@ -1550,6 +1551,10 @@ packages: resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} engines: {node: '>=14.17.0'} + '@egjs/hammerjs@2.0.17': + resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} + engines: {node: '>=0.8.0'} + '@emnapi/core@1.5.0': resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} @@ -1559,8 +1564,14 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@esbuild/aix-ppc64@0.25.10': - resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1571,8 +1582,14 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.10': - resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1583,8 +1600,14 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.10': - resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1595,8 +1618,14 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.10': - resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1607,8 +1636,14 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.10': - resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1619,8 +1654,14 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.10': - resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1631,8 +1672,14 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.10': - resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1643,8 +1690,14 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.10': - resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1655,8 +1708,14 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.10': - resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1667,8 +1726,14 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.10': - resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1679,8 +1744,14 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.10': - resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1691,8 +1762,14 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.10': - resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1703,8 +1780,14 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.10': - resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1715,8 +1798,14 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.10': - resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1727,8 +1816,14 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.10': - resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1739,8 +1834,14 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.10': - resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1751,8 +1852,14 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.10': - resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -1763,8 +1870,14 @@ packages: cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.10': - resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -1775,8 +1888,14 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.10': - resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1787,8 +1906,14 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.10': - resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -1799,8 +1924,14 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.10': - resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1811,8 +1942,14 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.10': - resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -1823,8 +1960,14 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.10': - resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1835,8 +1978,14 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.10': - resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1847,8 +1996,14 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.10': - resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1859,8 +2014,14 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.10': - resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1881,8 +2042,12 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.4.0': - resolution: {integrity: sha512-DEzm5dKeDBPm3r08Ixli/0cmxr8LkRdwxMRUIJBlSCpAwSrvFEJpVBzV+66JhDxiaqKxnRzCXhtiMiczF7Hglg==} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/compat@1.4.1': + resolution: {integrity: sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.40 || 9 @@ -1890,36 +2055,32 @@ packages: eslint: optional: true - '@eslint/config-array@0.21.0': - resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.3.1': - resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.15.2': - resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.16.0': - resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.36.0': - resolution: {integrity: sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==} + '@eslint/js@9.39.0': + resolution: {integrity: sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + '@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/plugin-kit@0.3.5': - resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@fortawesome/angular-fontawesome@2.0.1': @@ -1943,8 +2104,8 @@ packages: resolution: {integrity: sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==} engines: {node: '>=6'} - '@golevelup/ts-jest@0.6.2': - resolution: {integrity: sha512-ks82vcWbnRuwHSKlrZTGCPPWXZEKlsn1VA2OiYfJ+tVMcMsI4y9ExWkf7FnmYypYJIRWKS9b9N5QVVrCOmaVlg==} + '@golevelup/ts-jest@0.7.0': + resolution: {integrity: sha512-b5Kf+NiEfWuMGUD5bl/Gm/RqojS4Sr/4Q0ySXN4xn3xlkhgPYG6nGLBeNjk3MiM2I3ztVVFfI7SB8ajqDy6Idw==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -1962,12 +2123,12 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@inquirer/ansi@1.0.0': - resolution: {integrity: sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==} + '@inquirer/ansi@1.0.1': + resolution: {integrity: sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==} engines: {node: '>=18'} - '@inquirer/checkbox@4.2.4': - resolution: {integrity: sha512-2n9Vgf4HSciFq8ttKXk+qy+GsyTXPV1An6QAwe/8bkbbqvG4VW1I/ZY1pNu2rf+h9bdzMLPbRSfcNxkHBy/Ydw==} + '@inquirer/checkbox@4.3.0': + resolution: {integrity: sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -1984,8 +2145,8 @@ packages: '@types/node': optional: true - '@inquirer/confirm@5.1.18': - resolution: {integrity: sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==} + '@inquirer/confirm@5.1.19': + resolution: {integrity: sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -1993,8 +2154,8 @@ packages: '@types/node': optional: true - '@inquirer/core@10.2.2': - resolution: {integrity: sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==} + '@inquirer/core@10.3.0': + resolution: {integrity: sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2002,8 +2163,8 @@ packages: '@types/node': optional: true - '@inquirer/editor@4.2.20': - resolution: {integrity: sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==} + '@inquirer/editor@4.2.21': + resolution: {integrity: sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2011,8 +2172,8 @@ packages: '@types/node': optional: true - '@inquirer/expand@4.0.20': - resolution: {integrity: sha512-Dt9S+6qUg94fEvgn54F2Syf0Z3U8xmnBI9ATq2f5h9xt09fs2IJXSCIXyyVHwvggKWFXEY/7jATRo2K6Dkn6Ow==} + '@inquirer/expand@4.0.21': + resolution: {integrity: sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2029,12 +2190,12 @@ packages: '@types/node': optional: true - '@inquirer/figures@1.0.13': - resolution: {integrity: sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==} + '@inquirer/figures@1.0.14': + resolution: {integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==} engines: {node: '>=18'} - '@inquirer/input@4.2.4': - resolution: {integrity: sha512-cwSGpLBMwpwcZZsc6s1gThm0J+it/KIJ+1qFL2euLmSKUMGumJ5TcbMgxEjMjNHRGadouIYbiIgruKoDZk7klw==} + '@inquirer/input@4.2.5': + resolution: {integrity: sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2042,8 +2203,8 @@ packages: '@types/node': optional: true - '@inquirer/number@3.0.20': - resolution: {integrity: sha512-bbooay64VD1Z6uMfNehED2A2YOPHSJnQLs9/4WNiV/EK+vXczf/R988itL2XLDGTgmhMF2KkiWZo+iEZmc4jqg==} + '@inquirer/number@3.0.21': + resolution: {integrity: sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2051,8 +2212,8 @@ packages: '@types/node': optional: true - '@inquirer/password@4.0.20': - resolution: {integrity: sha512-nxSaPV2cPvvoOmRygQR+h0B+Av73B01cqYLcr7NXcGXhbmsYfUb8fDdw2Us1bI2YsX+VvY7I7upgFYsyf8+Nug==} + '@inquirer/password@4.0.21': + resolution: {integrity: sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2087,8 +2248,8 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@4.1.8': - resolution: {integrity: sha512-CQ2VkIASbgI2PxdzlkeeieLRmniaUU1Aoi5ggEdm6BIyqopE9GuDXdDOj9XiwOqK5qm72oI2i6J+Gnjaa26ejg==} + '@inquirer/rawlist@4.1.9': + resolution: {integrity: sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2096,8 +2257,8 @@ packages: '@types/node': optional: true - '@inquirer/search@3.1.3': - resolution: {integrity: sha512-D5T6ioybJJH0IiSUK/JXcoRrrm8sXwzrVMjibuPs+AgxmogKslaafy1oxFiorNI4s3ElSkeQZbhYQgLqiL8h6Q==} + '@inquirer/search@3.2.0': + resolution: {integrity: sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2105,8 +2266,8 @@ packages: '@types/node': optional: true - '@inquirer/select@4.3.4': - resolution: {integrity: sha512-Qp20nySRmfbuJBBsgPU7E/cL62Hf250vMZRzYDcBHty2zdD1kKCnoDFWRr0WO2ZzaXp3R7a4esaVGJUx0E6zvA==} + '@inquirer/select@4.4.0': + resolution: {integrity: sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2114,8 +2275,8 @@ packages: '@types/node': optional: true - '@inquirer/type@3.0.8': - resolution: {integrity: sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==} + '@inquirer/type@3.0.9': + resolution: {integrity: sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -2147,13 +2308,13 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} - '@jest/console@29.7.0': - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/console@30.2.0': + resolution: {integrity: sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/core@29.7.0': - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/core@30.2.0': + resolution: {integrity: sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -2164,57 +2325,55 @@ packages: resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jest/environment-jsdom-abstract@30.2.0': + resolution: {integrity: sha512-kazxw2L9IPuZpQ0mEt9lu9Z98SqR74xcagANmMBU16X0lS23yPc0+S6hGLUz8kVRlomZEs/5S/Zlpqwf5yu6OQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + jsdom: '*' + peerDependenciesMeta: + canvas: + optional: true + '@jest/environment@29.7.0': resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/environment@30.1.2': - resolution: {integrity: sha512-N8t1Ytw4/mr9uN28OnVf0SYE2dGhaIxOVYcwsf9IInBKjvofAjbFRvedvBBlyTYk2knbJTiEjEJ2PyyDIBnd9w==} + '@jest/environment@30.2.0': + resolution: {integrity: sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect-utils@29.7.0': - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/expect-utils@30.1.2': - resolution: {integrity: sha512-HXy1qT/bfdjCv7iC336ExbqqYtZvljrV8odNdso7dWK9bSeHtLlvwWWC3YSybSPL03Gg5rug6WLCZAZFH72m0A==} + '@jest/expect-utils@30.2.0': + resolution: {integrity: sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect@29.7.0': - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/expect@30.1.2': - resolution: {integrity: sha512-tyaIExOwQRCxPCGNC05lIjWJztDwk2gPDNSDGg1zitXJJ8dC3++G/CRjE5mb2wQsf89+lsgAgqxxNpDLiCViTA==} + '@jest/expect@30.2.0': + resolution: {integrity: sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/fake-timers@29.7.0': resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/fake-timers@30.1.2': - resolution: {integrity: sha512-Beljfv9AYkr9K+ETX9tvV61rJTY706BhBUtiaepQHeEGfe0DbpvUA5Z3fomwc5Xkhns6NWrcFDZn+72fLieUnA==} + '@jest/fake-timers@30.2.0': + resolution: {integrity: sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/get-type@30.1.0': resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/globals@29.7.0': - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/globals@30.1.2': - resolution: {integrity: sha512-teNTPZ8yZe3ahbYnvnVRDeOjr+3pu2uiAtNtrEsiMjVPPj+cXd5E/fr8BL7v/T7F31vYdEHrI5cC/2OoO/vM9A==} + '@jest/globals@30.2.0': + resolution: {integrity: sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/pattern@30.0.1': resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/reporters@29.7.0': - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/reporters@30.2.0': + resolution: {integrity: sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -2229,36 +2388,32 @@ packages: resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/snapshot-utils@30.1.2': - resolution: {integrity: sha512-vHoMTpimcPSR7OxS2S0V1Cpg8eKDRxucHjoWl5u4RQcnxqQrV3avETiFpl8etn4dqxEGarBeHbIBety/f8mLXw==} + '@jest/snapshot-utils@30.2.0': + resolution: {integrity: sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/source-map@29.6.3': - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/test-result@29.7.0': - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/test-sequencer@29.7.0': - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@30.2.0': + resolution: {integrity: sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@30.2.0': + resolution: {integrity: sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/transform@30.1.2': - resolution: {integrity: sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==} + '@jest/transform@30.2.0': + resolution: {integrity: sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/types@29.6.3': resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/types@30.0.5': - resolution: {integrity: sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==} + '@jest/types@30.2.0': + resolution: {integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jridgewell/gen-mapping@0.3.13': @@ -2289,8 +2444,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/buffers@1.0.0': - resolution: {integrity: sha512-NDigYR3PHqCnQLXYyoLbnEdzMMvzeiCWo1KOut7Q0CoIqg9tUAPKJ1iq/2nFhc5kZtexzutNY0LFjdwWL3Dw3Q==} + '@jsonjoy.com/buffers@1.2.1': + resolution: {integrity: sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -2301,8 +2456,8 @@ packages: peerDependencies: tslib: '2' - '@jsonjoy.com/json-pack@1.14.0': - resolution: {integrity: sha512-LpWbYgVnKzphN5S6uss4M25jJ/9+m6q6UJoeN6zTkK4xAGhKsiBRPVeF7OYMWonn5repMQbE5vieRXcMUrKDKw==} + '@jsonjoy.com/json-pack@1.21.0': + resolution: {integrity: sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -2517,9 +2672,6 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@napi-rs/wasm-runtime@1.0.5': - resolution: {integrity: sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==} - '@nestjs/cache-manager@3.0.1': resolution: {integrity: sha512-4UxTnR0fsmKL5YDalU2eLFVnL+OBebWUpX+hEduKGncrVKH4PPNoiRn1kXyOCjmzb0UvWgqubpssNouc8e0MCw==} peerDependencies: @@ -2542,8 +2694,8 @@ packages: '@swc/core': optional: true - '@nestjs/common@11.1.6': - resolution: {integrity: sha512-krKwLLcFmeuKDqngG2N/RuZHCs2ycsKcxWIDgcm7i1lf3sQ0iG03ci+DsP/r3FcT/eJDFsIHnKtNta2LIi7PzQ==} + '@nestjs/common@11.1.7': + resolution: {integrity: sha512-lwlObwGgIlpXSXYOTpfzdCepUyWomz6bv9qzGzzvpgspUxkj0Uz0fUJcvD44V8Ps7QhKW3lZBoYbXrH25UZrbA==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -2561,8 +2713,8 @@ packages: '@nestjs/common': ^10.0.0 || ^11.0.0 rxjs: ^7.1.0 - '@nestjs/core@11.1.6': - resolution: {integrity: sha512-siWX7UDgErisW18VTeJA+x+/tpNZrJewjTBsRPF3JVxuWRuAB1kRoiJcxHgln8Lb5UY9NdvklITR84DUEXD0Cg==} + '@nestjs/core@11.1.7': + resolution: {integrity: sha512-TyXFOwjhHv/goSgJ8i20K78jwTM0iSpk9GBcC2h3mf4MxNy+znI8m7nWjfoACjTkb89cTwDQetfTHtSfGLLaiA==} engines: {node: '>= 20'} peerDependencies: '@nestjs/common': ^11.0.0 @@ -2579,14 +2731,14 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/platform-express@11.1.6': - resolution: {integrity: sha512-HErwPmKnk+loTq8qzu1up+k7FC6Kqa8x6lJ4cDw77KnTxLzsCaPt+jBvOq6UfICmfqcqCCf3dKXg+aObQp+kIQ==} + '@nestjs/platform-express@11.1.7': + resolution: {integrity: sha512-5T+GLdvTiGPKB4/P4PM9ftKUKNHJy8ThEFhZA3vQnXVL7Vf0rDr07TfVTySVu+XTh85m1lpFVuyFM6u6wLNsRA==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 - '@nestjs/platform-socket.io@11.1.6': - resolution: {integrity: sha512-ozm+OKiRiFLNQdFLA3ULDuazgdVaPrdRdgtG/+404T7tcROXpbUuFL0eEmWJpG64CxMkBNwamclUSH6J0AeU7A==} + '@nestjs/platform-socket.io@11.1.7': + resolution: {integrity: sha512-suAyy5JWWvqU0fXbRp79Ihy7a1HSfB5rKgecVRmuQQyTi28W/0lsRsJN41plsxOEiXtaZq7sqiQp5Dg4XeUc9g==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/websockets': ^11.0.0 @@ -2598,13 +2750,13 @@ packages: '@nestjs/common': ^10.0.0 || ^11.0.0 '@nestjs/core': ^10.0.0 || ^11.0.0 - '@nestjs/schematics@11.0.7': - resolution: {integrity: sha512-t8dNYYMwEeEsrlwc2jbkfwCfXczq4AeNEgx1KVQuJ6wYibXk0ZbXbPdfp8scnEAaQv1grpncNV5gWgzi7ZwbvQ==} + '@nestjs/schematics@11.0.9': + resolution: {integrity: sha512-0NfPbPlEaGwIT8/TCThxLzrlz3yzDNkfRNpbL7FiplKq3w4qXpJg0JYwqgMEJnLQZm3L/L/5XjoyfJHUO3qX9g==} peerDependencies: typescript: '>=4.8.2' - '@nestjs/serve-static@5.0.3': - resolution: {integrity: sha512-0jFjTlSVSLrI+mot8lfm+h2laXtKzCvgsVStv9T1ZBZTDwS26gM5czIhIESmWAod0PfrbCDFiu9C1MglObL8VA==} + '@nestjs/serve-static@5.0.4': + resolution: {integrity: sha512-3kO1M9D3vsPyWPFardxIjUYeuolS58PnhCoBTkS7t3BrdZFZCKHnBZ15js+UOzOR2Q6HmD7ssGjLd0DVYVdvOw==} peerDependencies: '@fastify/static': ^8.0.4 '@nestjs/common': ^11.0.2 @@ -2619,8 +2771,8 @@ packages: fastify: optional: true - '@nestjs/testing@11.1.6': - resolution: {integrity: sha512-srYzzDNxGvVCe1j0SpTS9/ix75PKt6Sn6iMaH1rpJ6nj2g8vwNrhK0CoJJXvpCYgrnI+2WES2pprYnq8rAMYHA==} + '@nestjs/testing@11.1.8': + resolution: {integrity: sha512-E6K+0UTKztcPxJzLnQa7S34lFjZbrj3Z1r7c5y5WDrL1m5HD1H4AeyBhicHgdaFmxjLAva2bq0sYKy/S7cdeYA==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -2641,8 +2793,8 @@ packages: rxjs: ^7.2.0 typeorm: ^0.3.0 - '@nestjs/websockets@11.1.6': - resolution: {integrity: sha512-jlBX5QpqhfEVfxkwxTesIjgl0bdhgFMoORQYzjRg1i+Z+Qouf4KmjNPv5DZE3DZRDg91E+3Bpn0VgW0Yfl94ng==} + '@nestjs/websockets@11.1.7': + resolution: {integrity: sha512-FWPgZPN7yQWIeonQ7JL64Rbsbw/IQovft0cVC5UX1Jbsovq+rUaTuk3rilimGrawN9VOGcoiQLGNiIbmjjiCew==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -2653,8 +2805,8 @@ packages: '@nestjs/platform-socket.io': optional: true - '@ngtools/webpack@20.3.2': - resolution: {integrity: sha512-i5sbPfhQI6suMF+02KV3PzLBITlXZhiEKPjnQHUK/kCRc+tV+WQidxaO/UTkgSzqhzWGVHkmtE1Sau08K5Wi+A==} + '@ngtools/webpack@20.3.7': + resolution: {integrity: sha512-AlFf28hylqopJYz4P5MOGEmasOGtXntN/xExOuurP4P9xuUrO99FvaVm0+RPgw8iKeojNW5Bi6qFS77gLof56w==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} peerDependencies: '@angular/compiler-cli': ^20.0.0 @@ -2736,9 +2888,8 @@ packages: cpu: [arm64] os: [darwin] - '@nx/nx-darwin-x64@20.0.3': - resolution: {integrity: sha512-Gobgkvsx61P5TI0uuDQTI/D2AXJt3xnBuAWQ4V/NW/OpkvL8j/q8zk81uK0tumVvIc4p5kSlGmQ46/ytSrdqvg==} - engines: {node: '>= 10'} + '@nx/nx-darwin-x64@21.6.5': + resolution: {integrity: sha512-S/uW1tznZ5p93fOwcG+s+tuYI3aVIJKWTWI366XlusOj8yAHsDl1lI8dTp9ImN9kIdcgfF7/fr/zEMHpLLVvLg==} cpu: [x64] os: [darwin] @@ -2758,13 +2909,6 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@oxc-project/runtime@0.81.0': - resolution: {integrity: sha512-zm/LDVOq9FEmHiuM8zO4DWirv0VP2Tv2VsgaiHby9nvpq+FVrcqNYgv+TysLKOITQXWZj/roluTxFvpkHP0Iuw==} - engines: {node: '>=6.9.0'} - - '@oxc-project/types@0.81.0': - resolution: {integrity: sha512-CnOqkybZK8z6Gx7Wb1qF7AEnSzbol1WwcIzxYOr8e91LytGOjo0wCpgoYWZo8sdbpqX+X+TJayIzo4Pv0R/KjA==} - '@paralleldrive/cuid2@2.2.2': resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} @@ -2858,8 +3002,8 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@playwright/test@1.55.1': - resolution: {integrity: sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==} + '@playwright/test@1.57.0': + resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} engines: {node: '>=18'} hasBin: true @@ -2872,226 +3016,263 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@redis/bloom@5.8.2': - resolution: {integrity: sha512-855DR0ChetZLarblio5eM0yLwxA9Dqq50t8StXKp5bAtLT0G+rZ+eRzzqxl37sPqQKjUudSYypz55o6nNhbz0A==} + '@redis/bloom@5.8.3': + resolution: {integrity: sha512-1eldTzHvdW3Oi0TReb8m1yiFt8ZwyF6rv1NpZyG5R4TpCwuAdKQetBKoCw7D96tNFgsVVd6eL+NaGZZCqhRg4g==} engines: {node: '>= 18'} peerDependencies: - '@redis/client': ^5.8.2 + '@redis/client': ^5.8.3 - '@redis/client@5.8.2': - resolution: {integrity: sha512-WtMScno3+eBpTac1Uav2zugXEoXqaU23YznwvFgkPwBQVwEHTDgOG7uEAObtZ/Nyn8SmAMbqkEubJaMOvnqdsQ==} + '@redis/client@5.8.3': + resolution: {integrity: sha512-MZVUE+l7LmMIYlIjubPosruJ9ltSLGFmJqsXApTqPLyHLjsJUSAbAJb/A3N34fEqean4ddiDkdWzNu4ZKPvRUg==} engines: {node: '>= 18'} - '@redis/json@5.8.2': - resolution: {integrity: sha512-uxpVfas3I0LccBX9rIfDgJ0dBrUa3+0Gc8sEwmQQH0vHi7C1Rx1Qn8Nv1QWz5bohoeIXMICFZRcyDONvum2l/w==} + '@redis/json@5.8.3': + resolution: {integrity: sha512-DRR09fy/u8gynHGJ4gzXYeM7D8nlS6EMv5o+h20ndTJiAc7RGR01fdk2FNjnn1Nz5PjgGGownF+s72bYG4nZKQ==} engines: {node: '>= 18'} peerDependencies: - '@redis/client': ^5.8.2 + '@redis/client': ^5.8.3 - '@redis/search@5.8.2': - resolution: {integrity: sha512-cNv7HlgayavCBXqPXgaS97DRPVWFznuzsAmmuemi2TMCx5scwLiP50TeZvUS06h/MG96YNPe6A0Zt57yayfxwA==} + '@redis/search@5.8.3': + resolution: {integrity: sha512-EMIvEeGRR2I0BJEz4PV88DyCuPmMT1rDtznlsHY3cKSDcc9vj0Q411jUnX0iU2vVowUgWn/cpySKjpXdZ8m+5g==} engines: {node: '>= 18'} peerDependencies: - '@redis/client': ^5.8.2 + '@redis/client': ^5.8.3 - '@redis/time-series@5.8.2': - resolution: {integrity: sha512-g2NlHM07fK8H4k+613NBsk3y70R2JIM2dPMSkhIjl2Z17SYvaYKdusz85d7VYOrZBWtDrHV/WD2E3vGu+zni8A==} + '@redis/time-series@5.8.3': + resolution: {integrity: sha512-5Jwy3ilsUYQjzpE7WZ1lEeG1RkqQ5kHtwV1p8yxXHSEmyUbC/T/AVgyjMcm52Olj/Ov/mhDKjx6ndYUi14bXsw==} engines: {node: '>= 18'} peerDependencies: - '@redis/client': ^5.8.2 + '@redis/client': ^5.8.3 - '@rolldown/binding-android-arm64@1.0.0-beta.32': - resolution: {integrity: sha512-Gs+313LfR4Ka3hvifdag9r44WrdKQaohya7ZXUXzARF7yx0atzFlVZjsvxtKAw1Vmtr4hB/RjUD1jf73SW7zDw==} - cpu: [arm64] + '@rollup/rollup-android-arm-eabi@4.52.3': + resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==} + cpu: [arm] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.32': - resolution: {integrity: sha512-W8oMqzGcI7wKPXUtS3WJNXzbghHfNiuM1UBAGpVb+XlUCgYRQJd2PRGP7D3WGql3rR3QEhUvSyAuCBAftPQw6Q==} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.0-beta.32': - resolution: {integrity: sha512-pM4c4sKUk37noJrnnDkJknLhCsfZu7aWyfe67bD0GQHfzAPjV16wPeD9CmQg4/0vv+5IfHYaa4VE536xbA+W0Q==} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.0.0-beta.32': - resolution: {integrity: sha512-M8SUgFlYb5kJJWcFC8gUMRiX4WLFxPKMed3SJ2YrxontgIrEcpizPU8nLNVsRYEStoSfKHKExpQw3OP6fm+5bw==} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.32': - resolution: {integrity: sha512-FuQpbNC/hE//bvv29PFnk0AtpJzdPdYl5CMhlWPovd9g3Kc3lw9TrEPIbL7gRPUdhKAiq6rVaaGvOnXxsa0eww==} + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} cpu: [arm] - os: [linux] + os: [android] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.32': - resolution: {integrity: sha512-hRZygRlaGCjcNTNY9GV7dDI18sG1dK3cc7ujHq72LoDad23zFDUGMQjiSxHWK+/r92iMV+j2MiHbvzayxqynsg==} + '@rollup/rollup-android-arm64@4.52.3': + resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==} cpu: [arm64] - os: [linux] + os: [android] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.32': - resolution: {integrity: sha512-HzgT6h+CXLs+GKAU0Wvkt3rvcv0CmDBsDjlPhh4GHysOKbG9NjpKYX2zvjx671E9pGbTvcPpwy7gGsy7xpu+8g==} + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} cpu: [arm64] - os: [linux] - - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.32': - resolution: {integrity: sha512-Ab/wbf6gdzphDbsg51UaxsC93foQ7wxhtg0SVCXd25BrV4MAJ1HoDtKN/f4h0maFmJobkqYub2DlmoasUzkvBg==} - cpu: [x64] - os: [linux] - - '@rolldown/binding-linux-x64-musl@1.0.0-beta.32': - resolution: {integrity: sha512-VoxqGEfh5A1Yx+zBp/FR5QwAbtzbuvky2SVc+ii4g1gLD4zww6mt/hPi5zG+b88zYPFBKHpxMtsz9cWqXU5V5Q==} - cpu: [x64] - os: [linux] + os: [android] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.32': - resolution: {integrity: sha512-qZ1ViyOUDGbiZrSAJ/FIAhYUElDfVxxFW6DLT/w4KeoZN3HsF4jmRP95mXtl51/oGrqzU9l9Q2f7/P4O/o2ZZA==} + '@rollup/rollup-darwin-arm64@4.52.3': + resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==} cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.0-beta.32': - resolution: {integrity: sha512-hEkG3wD+f3wytV0lqwb/uCrXc4r4Ny/DWJFJPfQR3VeMWplhWGgSHNwZc2Q7k86Yi36f9NNzzWmrIuvHI9lCVw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] + os: [darwin] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.32': - resolution: {integrity: sha512-k3MvDf8SiA7uP2ikP0unNouJ2YCrnwi7xcVW+RDgMp5YXVr3Xu6svmT3HGn0tkCKUuPmf+uy8I5uiHt5qWQbew==} + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.32': - resolution: {integrity: sha512-wAi/FxGh7arDOUG45UmnXE1sZUa0hY4cXAO2qWAjFa3f7bTgz/BqwJ7XN5SUezvAJPNkME4fEpInfnBvM25a0w==} - cpu: [ia32] - os: [win32] + os: [darwin] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.32': - resolution: {integrity: sha512-Ej0i4PZk8ltblZtzVK8ouaGUacUtxRmTm5S9794mdyU/tYxXjAJNseOfxrnHpMWKjMDrOKbqkPqJ52T9NR4LQQ==} + '@rollup/rollup-darwin-x64@4.52.3': + resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==} cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.0-beta.32': - resolution: {integrity: sha512-QReCdvxiUZAPkvp1xpAg62IeNzykOFA6syH2CnClif4YmALN1XKpB39XneL80008UbtMShthSVDKmrx05N1q/g==} + os: [darwin] - '@rollup/rollup-android-arm-eabi@4.52.2': - resolution: {integrity: sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==} - cpu: [arm] - os: [android] + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} + cpu: [x64] + os: [darwin] - '@rollup/rollup-android-arm64@4.52.2': - resolution: {integrity: sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==} + '@rollup/rollup-freebsd-arm64@4.52.3': + resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==} cpu: [arm64] - os: [android] + os: [freebsd] - '@rollup/rollup-darwin-arm64@4.52.2': - resolution: {integrity: sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==} + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} cpu: [arm64] - os: [darwin] + os: [freebsd] - '@rollup/rollup-darwin-x64@4.52.2': - resolution: {integrity: sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==} + '@rollup/rollup-freebsd-x64@4.52.3': + resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==} cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.52.2': - resolution: {integrity: sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==} - cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.2': - resolution: {integrity: sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==} + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.2': - resolution: {integrity: sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==} + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': + resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.2': - resolution: {integrity: sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==} + '@rollup/rollup-linux-arm-musleabihf@4.52.3': + resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.2': - resolution: {integrity: sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==} + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.52.3': + resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.2': - resolution: {integrity: sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==} + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.52.2': - resolution: {integrity: sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==} + '@rollup/rollup-linux-arm64-musl@4.52.3': + resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.3': + resolution: {integrity: sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.2': - resolution: {integrity: sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==} + '@rollup/rollup-linux-ppc64-gnu@4.52.3': + resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.2': - resolution: {integrity: sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==} + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.52.3': + resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.2': - resolution: {integrity: sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==} + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.2': - resolution: {integrity: sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==} + '@rollup/rollup-linux-riscv64-musl@4.52.3': + resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.52.3': + resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.2': - resolution: {integrity: sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==} + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.52.3': + resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.52.3': + resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.2': - resolution: {integrity: sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==} + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.2': - resolution: {integrity: sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==} + '@rollup/rollup-openharmony-arm64@4.52.3': + resolution: {integrity: sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.2': - resolution: {integrity: sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==} + '@rollup/rollup-win32-arm64-msvc@4.52.3': + resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.2': - resolution: {integrity: sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==} + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.3': + resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.2': - resolution: {integrity: sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==} + '@rollup/rollup-win32-x64-gnu@4.52.3': + resolution: {integrity: sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.2': - resolution: {integrity: sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==} + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.3': + resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} cpu: [x64] os: [win32] '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@schematics/angular@19.2.17': - resolution: {integrity: sha512-FGNDJXjeCoYz3JMze3JReNOGkPsxLGs5LmLf5Zj3+BYYMsFoDUJD9BMRRf+tmc/epBkiZZtv80c8gmfhqGv4dA==} - engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@schematics/angular@20.3.7': + resolution: {integrity: sha512-jR2LPJVGK6yzPTNXkGJZYtdeLGkNdqJhVow2E+ILt3pk/LZuT/iSdr9V4nArU9yysifGuJFTyZapVOYkEYaykg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@schematics/angular@20.3.2': - resolution: {integrity: sha512-bd23C6Map7Rfrryc8pZuyPPG8yQLCH863ISo32ARVwiAmBFgjfyNwqC5FsuqHWrYlTzZDzZUk5CjKp1SXxqqxg==} + '@schematics/angular@20.3.8': + resolution: {integrity: sha512-lmdh1JywRl0BK1VcYwGDrNre78OpduNhsV4N5afELvrNPKSk/ixCb3iZq4MCY3yBZ3RV5Uso+vrJwwEeqe02JQ==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} '@sigstore/bundle@3.1.0': @@ -3142,8 +3323,8 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@stylistic/eslint-plugin@5.4.0': - resolution: {integrity: sha512-UG8hdElzuBDzIbjG1QDwnYH0MQ73YLXDFHgZzB4Zh/YJfnw8XNsloVtytqzx0I2Qky9THSdpTmi8Vjn/pf/Lew==} + '@stylistic/eslint-plugin@5.5.0': + resolution: {integrity: sha512-IeZF+8H0ns6prg4VrkhgL+yrvDXWDH2cKchrbh80ejG9dQgZWp10epHMbgRuQvgchLII/lfh6Xn3lu6+6L86Hw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=9.0.0' @@ -3171,8 +3352,8 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - '@ts-morph/common@0.27.0': - resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} + '@ts-morph/common@0.28.1': + resolution: {integrity: sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==} '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -3225,6 +3406,11 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/cookie-parser@1.4.10': + resolution: {integrity: sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==} + peerDependencies: + '@types/express': '*' + '@types/cookiejar@2.1.5': resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} @@ -3325,8 +3511,8 @@ packages: '@types/d3-zoom@3.0.8': resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} - '@types/d3@7.1.0': - resolution: {integrity: sha512-gYWvgeGjEl+zmF8c+U1RNIKqe7sfQwIXeLXO5Os72TjDjCEtgpvGBvZ8dXlAuSS1m6B90Y1Uo6Bm36OGR/OtCA==} + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -3337,23 +3523,23 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} + '@types/express-serve-static-core@4.19.7': + resolution: {integrity: sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==} - '@types/express-serve-static-core@5.0.7': - resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} + '@types/express-serve-static-core@5.1.0': + resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} - '@types/express@4.17.23': - resolution: {integrity: sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==} + '@types/express@4.17.25': + resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} - '@types/express@5.0.3': - resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} + '@types/express@5.0.5': + resolution: {integrity: sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==} '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/hammerjs@2.0.46': + resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} @@ -3361,6 +3547,9 @@ packages: '@types/http-proxy@1.17.16': resolution: {integrity: sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==} + '@types/http-proxy@1.17.17': + resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -3370,21 +3559,24 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - '@types/jasmine@5.1.9': - resolution: {integrity: sha512-8t4HtkW4wxiPVedMpeZ63n3vlWxEIquo/zc1Tm8ElU+SqVV7+D3Na2PWaJUp179AzTragMWVwkMv7mvty0NfyQ==} - - '@types/jest@29.5.14': - resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} '@types/jsdom@20.0.1': resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + '@types/jsdom@21.1.7': + resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/jsonwebtoken@9.0.10': + resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} + '@types/luxon@3.4.2': resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} @@ -3400,11 +3592,14 @@ packages: '@types/mousetrap@1.6.15': resolution: {integrity: sha512-qL0hyIMNPow317QWW/63RvL1x5MVMV+Ru3NaY9f/CuEpCqrmb7WeuK2071ZY5hczOnm38qExWM2i2WtkXLSqFw==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node-forge@1.3.14': resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} - '@types/node@22.18.6': - resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} + '@types/node@24.9.2': + resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==} '@types/pako@2.0.4': resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==} @@ -3421,14 +3616,20 @@ packages: '@types/retry@0.12.2': resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} - '@types/send@0.17.5': - resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} + '@types/send@0.17.6': + resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} + + '@types/send@1.2.0': + resolution: {integrity: sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==} + + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} '@types/serve-index@1.9.4': resolution: {integrity: sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==} - '@types/serve-static@1.15.8': - resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==} + '@types/serve-static@1.15.10': + resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} '@types/sockjs@0.3.36': resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} @@ -3463,63 +3664,100 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@8.44.1': - resolution: {integrity: sha512-molgphGqOBT7t4YKCSkbasmu1tb1MgrZ2szGzHbclF7PNmOkSTQVHy+2jXOSnxvR3+Xe1yySHFZoqMpz3TfQsw==} + '@typescript-eslint/eslint-plugin@8.46.2': + resolution: {integrity: sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.44.1 + '@typescript-eslint/parser': ^8.46.2 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.44.1': - resolution: {integrity: sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==} + '@typescript-eslint/parser@8.46.2': + resolution: {integrity: sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.44.1': - resolution: {integrity: sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA==} + '@typescript-eslint/project-service@8.46.1': + resolution: {integrity: sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.46.2': + resolution: {integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.44.1': - resolution: {integrity: sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==} + '@typescript-eslint/scope-manager@8.46.1': + resolution: {integrity: sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.44.1': - resolution: {integrity: sha512-B5OyACouEjuIvof3o86lRMvyDsFwZm+4fBOqFHccIctYgBjqR3qT39FBYGN87khcgf0ExpdCBeGKpKRhSFTjKQ==} + '@typescript-eslint/scope-manager@8.46.2': + resolution: {integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.46.1': + resolution: {integrity: sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/tsconfig-utils@8.46.2': + resolution: {integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.44.1': - resolution: {integrity: sha512-KdEerZqHWXsRNKjF9NYswNISnFzXfXNDfPxoTh7tqohU/PRIbwTmsjGK6V9/RTYWau7NZvfo52lgVk+sJh0K3g==} + '@typescript-eslint/type-utils@8.46.2': + resolution: {integrity: sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.44.1': - resolution: {integrity: sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==} + '@typescript-eslint/types@8.46.1': + resolution: {integrity: sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.44.1': - resolution: {integrity: sha512-qnQJ+mVa7szevdEyvfItbO5Vo+GfZ4/GZWWDRRLjrxYPkhM+6zYB2vRYwCsoJLzqFCdZT4mEqyJoyzkunsZ96A==} + '@typescript-eslint/types@8.46.2': + resolution: {integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.46.1': + resolution: {integrity: sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.44.1': - resolution: {integrity: sha512-DpX5Fp6edTlocMCwA+mHY8Mra+pPjRZ0TfHkXI8QFelIKcbADQz1LUPNtzOFUriBB2UYqw4Pi9+xV4w9ZczHFg==} + '@typescript-eslint/typescript-estree@8.46.2': + resolution: {integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.46.1': + resolution: {integrity: sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.46.2': + resolution: {integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.44.1': - resolution: {integrity: sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==} + '@typescript-eslint/visitor-keys@8.46.1': + resolution: {integrity: sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/visitor-keys@8.46.2': + resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -3620,6 +3858,10 @@ packages: cpu: [x64] os: [win32] + '@vercel/oidc@3.0.3': + resolution: {integrity: sha512-yNEQvPcVrK9sIe637+I0jD6leluPxzwJKx/Haw6F4H77CdDsszUn5V3o96LPziXkSNE2B83+Z3mjqGKBK/R6Gg==} + engines: {node: '>= 20'} + '@vitejs/plugin-basic-ssl@2.1.0': resolution: {integrity: sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -3738,11 +3980,11 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ai@5.0.40: - resolution: {integrity: sha512-AEKVjVQjnzomEz39f1axnCLtmNRU/BrP12Ou6ztinGhv5u1VxrrRk5qbXugVI0ijeaVwxKQ/SWs0dicUC0qLEA==} + ai@5.0.80: + resolution: {integrity: sha512-g1o6pjxm1eTtyh295dRhsg0gvZaHFlSo2oruWrK2rIR7KafWEhNB2A2/aJ9hyPT9AMI8JnQJyto1Tl9DMqwc9w==} engines: {node: '>=18'} peerDependencies: - zod: ^3.25.76 || ^4 + zod: ^3.25.76 || ^4.1.8 ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -3784,8 +4026,8 @@ packages: resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} engines: {node: '>=0.4.2'} - angular-eslint@20.3.0: - resolution: {integrity: sha512-MvmeFuPmJHRmfL1A9IMtZJEYaU6sF++saJgpsU7aOD6YDZCGJ0J6HxlJ/q7YRbWYuI1q+gF/qALxdnuwHYadSg==} + angular-eslint@20.5.0: + resolution: {integrity: sha512-TSZWjLl3NF6C+PV4wEs6EV1lw+ENo6aOkLCoZ41jXB2bmSvH76LqgTLzWtVNaSZE/MmAL0RkDJFyRtGcE4dtgQ==} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '*' @@ -3929,11 +4171,11 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-jest@30.2.0: + resolution: {integrity: sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.8.0 + '@babel/core': ^7.11.0 || ^8.0.0-0 babel-loader@10.0.0: resolution: {integrity: sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==} @@ -3942,17 +4184,13 @@ packages: '@babel/core': ^7.12.0 webpack: '>=5.61.0' - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - babel-plugin-istanbul@7.0.1: resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} engines: {node: '>=12'} - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-jest-hoist@30.2.0: + resolution: {integrity: sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} babel-plugin-polyfill-corejs2@0.4.14: resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} @@ -3974,11 +4212,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0 || ^8.0.0-0 - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-preset-jest@30.2.0: + resolution: {integrity: sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -3994,8 +4232,12 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} - baseline-browser-mapping@2.8.6: - resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==} + baseline-browser-mapping@2.8.17: + resolution: {integrity: sha512-j5zJcx6golJYTG6c05LUZ3Z8Gi+M62zRT/ycz4Xq4iCOdpcxwg7ngEYD4KA0eWZC7U17qh/Smq8bYbACJ0ipBA==} + hasBin: true + + baseline-browser-mapping@2.8.20: + resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==} hasBin: true basic-auth@2.0.1: @@ -4050,8 +4292,13 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.26.2: - resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==} + browserslist@4.26.3: + resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + browserslist@4.27.0: + resolution: {integrity: sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -4062,6 +4309,9 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -4087,8 +4337,8 @@ packages: resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} engines: {node: ^18.17.0 || >=20.5.0} - cache-manager@6.4.3: - resolution: {integrity: sha512-VV5eq/QQ5rIVix7/aICO4JyvSeEv9eIQuKL5iFwgM2BrcYoE0A/D1mNsAHJAsB0WEbNdBlKkn6Tjz6fKzh/cKQ==} + cache-manager@7.2.4: + resolution: {integrity: sha512-skmhkqXjPCBmrb70ctEx4zwFk7vb0RdFXlVGYWnFZ8pKvkzdFrFFKSJ1IaKduGfkryHOJvb7q2PkGmonmL+UGw==} call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} @@ -4117,8 +4367,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001743: - resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==} + caniuse-lite@1.0.30001751: + resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} canvg@3.0.11: resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==} @@ -4170,12 +4420,12 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - ci-info@4.3.0: - resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==} + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + cjs-module-lexer@2.1.0: + resolution: {integrity: sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==} cjson@0.3.0: resolution: {integrity: sha512-bBRQcCIHzI1IVH59fR0bwGrFmi3Btb/JNwM/n401i1DnYgWndpsUBiQRAddLflkZage20A2d25OAWZZk0vBRlA==} @@ -4235,8 +4485,8 @@ packages: code-block-writer@13.0.3: resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} - collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -4264,8 +4514,8 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - commander@14.0.1: - resolution: {integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==} + commander@14.0.2: + resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} engines: {node: '>=20'} commander@2.20.3: @@ -4279,8 +4529,8 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} - comment-json@4.2.5: - resolution: {integrity: sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==} + comment-json@4.4.1: + resolution: {integrity: sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==} engines: {node: '>= 6'} component-emitter@1.3.1: @@ -4301,8 +4551,8 @@ packages: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} engines: {'0': node >= 6.0} - concurrently@9.1.2: - resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==} + concurrently@9.2.1: + resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} engines: {node: '>=18'} hasBin: true @@ -4336,6 +4586,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-parser@1.4.7: + resolution: {integrity: sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==} + engines: {node: '>= 0.8.0'} + cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -4363,11 +4617,11 @@ packages: peerDependencies: webpack: ^5.1.0 - core-js-compat@3.45.1: - resolution: {integrity: sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==} + core-js-compat@3.46.0: + resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} - core-js@3.45.1: - resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==} + core-js@3.46.0: + resolution: {integrity: sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -4392,12 +4646,7 @@ packages: typescript: '>=4.9.5' peerDependenciesMeta: typescript: - optional: true - - create-jest@29.7.0: - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true + optional: true create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -4583,8 +4832,8 @@ packages: resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} engines: {node: '>=12'} - d3@7.6.1: - resolution: {integrity: sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==} + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} engines: {node: '>=12'} data-urls@3.0.2: @@ -4715,8 +4964,8 @@ packages: engines: {node: '>=0.10'} hasBin: true - detect-libc@2.1.1: - resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} detect-newline@3.1.0: @@ -4729,10 +4978,6 @@ packages: dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -4760,8 +5005,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.2.4: - resolution: {integrity: sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==} + dompurify@3.3.0: + resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==} domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -4794,26 +5039,24 @@ packages: ebnf-parser@0.1.10: resolution: {integrity: sha512-urvSxVQ6XJcoTpc+/x2pWhhuOX4aljCNQpwzw+ifZvV1andZkAmiJc3Rq1oGEAQmcjiLceyMXOy1l8ms8qs2fQ==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - ejs@3.1.10: - resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} - engines: {node: '>=0.10.0'} - hasBin: true + electron-to-chromium@1.5.237: + resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==} - electron-to-chromium@1.5.223: - resolution: {integrity: sha512-qKm55ic6nbEmagFlTFczML33rF90aU+WtrJ9MdTCThrcvDNdUHN4p6QfVN78U06ZmguqXIyMPyYhw2TrbDUwPQ==} - - emitter-component@1.1.2: - resolution: {integrity: sha512-QdXO3nXOzZB4pAjM0n6ZE+R9/+kPpECA/XSELIcc54NeYVnBqIk+4DFiBgK+8QbV3mdvTG6nedl7dTYgO+5wDw==} + electron-to-chromium@1.5.240: + resolution: {integrity: sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} - emoji-regex@10.5.0: - resolution: {integrity: sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -4917,8 +5160,8 @@ packages: es6-shim@0.35.8: resolution: {integrity: sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==} - esbuild-wasm@0.25.10: - resolution: {integrity: sha512-IyyfrTA2iiOh/uhlaJj0aUDgW42lFhr29ZeKouVNOz/8mLyuqWbEuVst+B4RBH18pb3AcOHnaOgyskAbsVOe3A==} + esbuild-wasm@0.25.11: + resolution: {integrity: sha512-60gllbYFIRGzB6KALBB5Va9Wy3VeCi2U0NgmM7r+TFnRgzeEyoCn2D7fhacW2zWbd7MUeTKLDE7RlfYGBQ00bw==} engines: {node: '>=18'} hasBin: true @@ -4927,8 +5170,13 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.25.10: - resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true @@ -5075,8 +5323,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.36.0: - resolution: {integrity: sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==} + eslint@9.39.0: + resolution: {integrity: sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -5160,20 +5408,16 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} engines: {node: '>= 0.8.0'} - expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - expect@30.1.2: - resolution: {integrity: sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg==} + expect@30.2.0: + resolution: {integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} express-rate-limit@7.5.1: resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} @@ -5248,9 +5492,6 @@ packages: resolution: {integrity: sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg==} engines: {node: '>=20'} - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -5378,6 +5619,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -5414,8 +5659,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.12.0: + resolution: {integrity: sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -5425,8 +5670,8 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regex.js@1.0.1: - resolution: {integrity: sha512-CG/iEvgQqfzoVsMUbxSJcwbG2JwyZ3naEqPkeltwl0BSS8Bp83k3xlGms+0QdWFUAwV+uvo80wNswKF6FWEkKg==} + glob-to-regex.js@1.2.0: + resolution: {integrity: sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' @@ -5451,12 +5696,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} - engines: {node: '>=18'} - - globals@16.4.0: - resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} globalthis@1.0.4: @@ -5473,10 +5714,6 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - hammerjs@2.0.8: - resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==} - engines: {node: '>=0.8.0'} - handle-thing@2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} @@ -5493,10 +5730,6 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-own-prop@2.0.0: - resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==} - engines: {node: '>=8'} - has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -5520,8 +5753,8 @@ packages: resolution: {integrity: sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==} engines: {node: ^18.17.0 || >=20.5.0} - hosted-git-info@9.0.0: - resolution: {integrity: sha512-gEf705MZLrDPkbbhi8PnoO4ZwYgKoNL+ISZ3AjZMht2r3N5tuTwncyDi6Fv2/qDnMmZxgs0yI8WDOyR8q3G+SQ==} + hosted-git-info@9.0.2: + resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} engines: {node: ^20.17.0 || >=22.9.0} hpack.js@2.1.6: @@ -5614,8 +5847,8 @@ packages: resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} engines: {node: '>=10.18'} - i18next@25.5.2: - resolution: {integrity: sha512-lW8Zeh37i/o0zVr+NoCHfNnfvVw+M6FQbRp36ZZ/NyHDJ3NJVpp2HhAUyU9WafL5AssymNoOjMRB48mmx2P6Hw==} + i18next@25.5.3: + resolution: {integrity: sha512-joFqorDeQ6YpIXni944upwnuHBf5IoPMuqAchGVeQLdWC2JOjxgM9V8UGLhNIIH/Q8QleRxIi0BSRQehSrDLcg==} peerDependencies: typescript: ^5 peerDependenciesMeta: @@ -5663,8 +5896,8 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - immutable@5.1.3: - resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + immutable@5.1.4: + resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -5792,8 +6025,8 @@ packages: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -5935,10 +6168,6 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - istanbul-lib-instrument@6.0.3: resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} @@ -5947,8 +6176,8 @@ packages: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} istanbul-reports@3.2.0: @@ -5966,25 +6195,20 @@ packages: resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} engines: {node: 20 || >=22} - jake@10.9.4: - resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} - engines: {node: '>=10'} - hasBin: true - jest-canvas-mock@2.5.2: resolution: {integrity: sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==} - jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-changed-files@30.2.0: + resolution: {integrity: sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-circus@30.2.0: + resolution: {integrity: sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-cli@29.7.0: - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-cli@30.2.0: + resolution: {integrity: sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -5992,33 +6216,32 @@ packages: node-notifier: optional: true - jest-config@29.7.0: - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-config@30.2.0: + resolution: {integrity: sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@types/node': '*' + esbuild-register: '>=3.4.0' ts-node: '>=9.0.0' peerDependenciesMeta: '@types/node': optional: true + esbuild-register: + optional: true ts-node: optional: true - jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-diff@30.1.2: - resolution: {integrity: sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==} + jest-diff@30.2.0: + resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@30.2.0: + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-each@30.2.0: + resolution: {integrity: sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-environment-jsdom@29.7.0: resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} @@ -6029,52 +6252,36 @@ packages: canvas: optional: true - jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-haste-map@30.1.0: - resolution: {integrity: sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==} + jest-environment-node@30.2.0: + resolution: {integrity: sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-jasmine2@29.7.0: - resolution: {integrity: sha512-N3nRpBVTM5erHtMi6ODBUEqG/LpVgSJC8qk14duw88d9Eigx2vL+n4LF1d8eV8pegnnzKyNHdTGxa/NsIKj0Zw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@30.2.0: + resolution: {integrity: sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-leak-detector@30.2.0: + resolution: {integrity: sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-matcher-utils@30.1.2: - resolution: {integrity: sha512-7ai16hy4rSbDjvPTuUhuV8nyPBd6EX34HkBsBcBX2lENCuAQ0qKCPb/+lt8OSWUa9WWmGYLy41PrEzkwRwoGZQ==} + jest-matcher-utils@30.2.0: + resolution: {integrity: sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-message-util@30.1.0: - resolution: {integrity: sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==} + jest-message-util@30.2.0: + resolution: {integrity: sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-mock@29.7.0: resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-mock@30.0.5: - resolution: {integrity: sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==} + jest-mock@30.2.0: + resolution: {integrity: sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-pnp-resolver@1.2.3: @@ -6100,83 +6307,69 @@ packages: jsdom: optional: true - jest-preset-angular@14.6.1: - resolution: {integrity: sha512-7q5x42wKrsF2ykOwGVzcXpr9p1X4FQJMU/DnH1tpvCmeOm5XqENdwD/xDZug+nP6G8SJPdioauwdsK/PMY/MpQ==} - engines: {node: ^14.15.0 || >=16.10.0} + jest-preset-angular@15.0.3: + resolution: {integrity: sha512-W1OpeQ/tq72ZSGXRvUDktL02QBAWIM5SZPK4KI0zoXNvRGiGhNMbxuaFF7anLi27cojmWHm+TewJQI1Dsm9s6A==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0} peerDependencies: - '@angular/compiler-cli': '>=15.0.0 <21.0.0' - '@angular/core': '>=15.0.0 <21.0.0' - '@angular/platform-browser-dynamic': '>=15.0.0 <21.0.0' - jest: ^29.0.0 - jsdom: '>=20.0.0' - typescript: '>=4.8' - peerDependenciesMeta: - jsdom: - optional: true - - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@angular/compiler-cli': '>=18.0.0 <21.0.0' + '@angular/core': '>=18.0.0 <21.0.0' + '@angular/platform-browser': '>=18.0.0 <21.0.0' + '@angular/platform-browser-dynamic': '>=18.0.0 <21.0.0' + jest: ^30.0.0 + jsdom: '>=26.0.0' + typescript: '>=5.5' jest-regex-util@30.0.1: resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve-dependencies@30.2.0: + resolution: {integrity: sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve@30.2.0: + resolution: {integrity: sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@30.2.0: + resolution: {integrity: sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runtime@30.2.0: + resolution: {integrity: sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-snapshot@30.1.2: - resolution: {integrity: sha512-4q4+6+1c8B6Cy5pGgFvjDy/Pa6VYRiGu0yQafKkJ9u6wQx4G5PqI2QR6nxTl43yy7IWsINwz6oT4o6tD12a8Dg==} + jest-snapshot@30.2.0: + resolution: {integrity: sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-util@30.0.5: - resolution: {integrity: sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==} + jest-util@30.2.0: + resolution: {integrity: sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-validate@30.2.0: + resolution: {integrity: sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-watcher@30.2.0: + resolution: {integrity: sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-worker@30.1.0: - resolution: {integrity: sha512-uvWcSjlwAAgIu133Tt77A05H7RIk3Ho8tZL50bQM2AkvLdluw9NG48lRCl3Dt+MOH719n/0nnb5YxUwcuJiKRA==} + jest-worker@30.2.0: + resolution: {integrity: sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest@29.7.0: - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest@30.2.0: + resolution: {integrity: sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -6269,9 +6462,19 @@ packages: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + jspdf@3.0.3: resolution: {integrity: sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==} + jwa@1.4.2: + resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} + + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + karma-source-map-support@1.4.0: resolution: {integrity: sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==} @@ -6281,17 +6484,13 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - keyv@5.5.2: - resolution: {integrity: sha512-TXcFHbmm/z7MGd1u9ASiCSfTS+ei6Z8B3a5JHzx3oPa/o7QzWVtPRpc4KGER5RR469IC+/nfg4U5YLIuDUua2g==} + keyv@5.5.3: + resolution: {integrity: sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A==} kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - launch-editor@2.11.1: resolution: {integrity: sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==} @@ -6324,8 +6523,8 @@ packages: lex-parser@0.1.4: resolution: {integrity: sha512-DuAEISsr1H4LOpmFLkyMc8YStiRWZCO8hMsoXAXSbgyfvs2WQhSt0+/FBv3ZU/JBFZMGcE+FWzEBSzwUU7U27w==} - libphonenumber-js@1.12.22: - resolution: {integrity: sha512-nzdkDyqlcLV754o1RrOJxh8kycG+63odJVUqnK4dxhw7buNkdTqJc/a/CE0h599dTJgFbzvr6GEOemFBSBryAA==} + libphonenumber-js@1.12.24: + resolution: {integrity: sha512-l5IlyL9AONj4voSd7q9xkuQOL4u8Ty44puTic7J88CmdXkxfGsRfoVLXHCxppwehgpb/Chdb80FFehHqjN3ItQ==} license-webpack-plugin@4.0.2: resolution: {integrity: sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==} @@ -6349,12 +6548,12 @@ packages: resolution: {integrity: sha512-nwVGUfTBUwJKXd6lRV8pFNfnrCC1+l49ESJRM19t/tFb/97QfJEixe5DYRvug5JO7DSFKoKaVy7oGMt5rVqZvg==} hasBin: true - load-esm@1.0.2: - resolution: {integrity: sha512-nVAvWk/jeyrWyXEAs84mpQCYccxRqgKY4OznLuJhJCa0XsPSfdOIr2zvBZEj3IHEHbX97jjscKRRV539bW0Gpw==} + load-esm@1.0.3: + resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} engines: {node: '>=13.2.0'} - loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} loader-utils@2.0.4: @@ -6379,12 +6578,33 @@ packages: lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + 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==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -6481,8 +6701,8 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} - memfs@4.46.0: - resolution: {integrity: sha512-//IxqL9OO/WMpm2kE2aq+y7vO7/xS9xgVIbFM8RUIfW7TY7lowtnuS1j9MwLGm0OwcHUa4p8Bp+40W7f1BiWGQ==} + memfs@4.49.0: + resolution: {integrity: sha512-L9uC9vGuc4xFybbdOpRLoOAOq1YEBBsocCs5NVW32DfU+CZWWIn3OVF+lB8Gp4ttBVSMazwrTrjv8ussX/e3VQ==} merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -6549,17 +6769,13 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@10.0.3: - resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -6616,9 +6832,6 @@ packages: engines: {node: '>=10'} hasBin: true - moment@2.30.1: - resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - moo-color@1.0.3: resolution: {integrity: sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==} @@ -6663,8 +6876,8 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - napi-postinstall@0.3.3: - resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==} + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true @@ -6729,16 +6942,19 @@ packages: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true - node-gyp@11.4.2: - resolution: {integrity: sha512-3gD+6zsrLQH7DyYOUIutaauuXrcyxeTPyQuZQCQoNPZMHMMS5m4y0xclNpvYzoK3VNzuyxT6eF4mkIL4WSZ1eQ==} + node-gyp@11.5.0: + resolution: {integrity: sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.21: - resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} + node-releases@2.0.25: + resolution: {integrity: sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==} + + node-releases@2.0.26: + resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} nomnom@1.5.2: resolution: {integrity: sha512-fiVbT7BqxiQqjlR9U3FDGOSERFCKoXVCdxV2FwZuNN7/cmJ42iQx35nUFOAFDcyvemu9Adp+IlsCGlKQYLmBKw==} @@ -6777,8 +6993,8 @@ packages: resolution: {integrity: sha512-+t2etZAGcB7TbbLHfDwooV9ppB2LhhcT6A+L9cahsf9mEUAoQ6CktLEVvEnpD0N5CkX7zJqnPGaFtoQDy9EkHQ==} engines: {node: ^20.17.0 || >=22.9.0} - npm-packlist@10.0.2: - resolution: {integrity: sha512-DrIWNiWT0FTdDRjGOYfEEZUNe1IzaSZ+up7qBTKnrQDySpdmuOQvytrqQlpK5QrCA4IThMvL4wTumqaa1ZvVIQ==} + npm-packlist@10.0.3: + resolution: {integrity: sha512-zPukTwJMOu5X5uvm0fztwS5Zxyvmk38H/LfidkOMt3gbZVCyro2cD/ETzwzVPcWZA3JOyPznfUN/nkyFiyUbxg==} engines: {node: ^20.17.0 || >=22.9.0} npm-pick-manifest@10.0.0: @@ -6994,9 +7210,8 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - path-to-regexp@8.2.0: - resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} - engines: {node: '>=16'} + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -7077,13 +7292,13 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} - playwright-core@1.55.1: - resolution: {integrity: sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==} + playwright-core@1.57.0: + resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} engines: {node: '>=18'} hasBin: true - playwright@1.55.1: - resolution: {integrity: sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==} + playwright@1.57.0: + resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} engines: {node: '>=18'} hasBin: true @@ -7185,8 +7400,8 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pretty-format@30.0.5: - resolution: {integrity: sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==} + pretty-format@30.2.0: + resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} prismjs@1.30.0: @@ -7197,6 +7412,10 @@ packages: resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} engines: {node: ^18.17.0 || >=20.5.0} + proc-log@6.0.0: + resolution: {integrity: sha512-KG/XsTDN901PNfPfAMmj6N/Ywg9tM+bHK8pAz+27fS4N4Pcr+4zoYBOcGSBu6ceXYNPxkLpa4ohtfxV1XcLAfA==} + engines: {node: ^20.17.0 || >=22.9.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -7204,13 +7423,6 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - propagating-hammerjs@1.5.0: - resolution: {integrity: sha512-3PUXWmomwutoZfydC+lJwK1bKCh6sK6jZGB31RUX6+4EXzsbkDZrK4/sVR7gBrvJaEIwpTVyxQUAd29FKkmVdw==} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -7232,11 +7444,11 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - qr-code-styling@1.9.1: - resolution: {integrity: sha512-T/VxQchuZkQwYhIcyyMUmtXHPeDT6lJBYHfqGD5CBDyIjswxS7JZKf443q+SXO1K/9SUswi6JpXEUQ5AoMCpyg==} + qr-code-styling@1.9.2: + resolution: {integrity: sha512-RgJaZJ1/RrXJ6N0j7a+pdw3zMBmzZU4VN2dtAZf8ZggCfRB5stEQ3IoDNGaNhYY3nnZKYlYSLl5YkfWN5dPutg==} engines: {node: '>=18.18.0'} qrcode-generator@1.5.2: @@ -7292,8 +7504,8 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - redis@5.8.2: - resolution: {integrity: sha512-31vunZj07++Y1vcFGcnNWEf5jPoTkGARgfWI4+Tk55vdwHxhAvug8VEtW7Cx+/h47NuJTEg/JL77zAwC6E0OeA==} + redis@5.8.3: + resolution: {integrity: sha512-MfSrfV6+tEfTw8c4W0yFp6XWX8Il4laGU7Bx4kvW4uiYM1AuZ3KGqEGt1LdQHeD1nEyLpIWetZ/SpY3kkbgrYw==} engines: {node: '>= 18'} reflect-metadata@0.2.2: @@ -7331,10 +7543,6 @@ packages: resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true - repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -7369,15 +7577,16 @@ packages: resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==} engines: {node: '>=12'} - resolve.exports@2.0.3: - resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} - engines: {node: '>=10'} - resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} hasBin: true + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -7413,12 +7622,13 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} - rolldown@1.0.0-beta.32: - resolution: {integrity: sha512-vxI2sPN07MMaoYKlFrVva5qZ1Y7DAZkgp7MQwTnyHt4FUMz9Sh+YeCzNFV9JYHI6ZNwoGWLCfCViE3XVsRC1cg==} + rollup@4.52.3: + resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rollup@4.52.2: - resolution: {integrity: sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==} + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -7500,8 +7710,8 @@ packages: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} - schema-utils@4.3.2: - resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} select-hose@2.0.0: @@ -7524,6 +7734,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} @@ -7617,9 +7832,6 @@ packages: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -7874,8 +8086,8 @@ packages: resolution: {integrity: sha512-cZZXK3G089PbpxH8N7vN7Z21SEKqXAaCiSVOmZdR/v7z8TFCsF/OFr0rzjhQuFlQQHy9uQtW9P2oQFJzJFGVrg==} engines: {node: '>= 16', npm: '>= 8'} - tapable@2.2.3: - resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} tar@6.2.1: @@ -7942,8 +8154,8 @@ packages: tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - to-buffer@1.2.1: - resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} engines: {node: '>= 0.4'} to-regex-range@5.0.1: @@ -7990,8 +8202,8 @@ packages: peerDependencies: typescript: '>=4.8.4' - ts-jest@29.4.0: - resolution: {integrity: sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==} + ts-jest@29.4.5: + resolution: {integrity: sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -8024,8 +8236,8 @@ packages: typescript: '*' webpack: ^5.0.0 - ts-morph@26.0.0: - resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} + ts-morph@27.0.2: + resolution: {integrity: sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==} ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} @@ -8164,8 +8376,8 @@ packages: typeorm-aurora-data-api-driver: optional: true - typescript-eslint@8.44.1: - resolution: {integrity: sha512-0ws8uWGrUVTjEeN2OM4K1pLKHK/4NiNP/vz6ns+LjT/6sqpaYzIVFajZb1fj/IDwpsrrHb3Jy0Qm5u9CPcKaeg==} + typescript-eslint@8.46.2: + resolution: {integrity: sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -8176,6 +8388,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + 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'} @@ -8196,8 +8413,8 @@ packages: underscore@1.1.7: resolution: {integrity: sha512-w4QtCHoLBXw1mjofIDoMyexaEdWGMedWNDhlWTtT1V1lCRqi65Pnoygkh6+WRdr+Bm8ldkBNkNeCsXGMlQS9HQ==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} undici@7.16.0: resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} @@ -8251,6 +8468,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -8297,23 +8520,42 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vis@4.21.0-EOL: - resolution: {integrity: sha512-JVS1mywKg5S88XbkDJPfCb3n+vlg5fMA8Ae2hzs3KHAwD4ryM5qwlbFZ6ReDfY8te7I4NLCpuCoywJQEehvJlQ==} - deprecated: Please consider using https://github.com/visjs + vis-data@8.0.3: + resolution: {integrity: sha512-jhnb6rJNqkKR1Qmlay0VuDXY9ZlvAnYN1udsrP4U+krgZEq7C0yNSKdZqmnCe13mdnf9AdVcdDGFOzy2mpPoqw==} + peerDependencies: + uuid: ^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^13.0.0 + vis-util: '>=6.0.0' - vite@6.3.6: - resolution: {integrity: sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vis-network@10.0.2: + resolution: {integrity: sha512-qPl8GLYBeHEFqiTqp4VBbYQIJ2EA8KLr7TstA2E8nJxfEHaKCU81hQLz7hhq11NUpHbMaRzBjW5uZpVKJ45/wA==} + peerDependencies: + '@egjs/hammerjs': ^2.0.0 + component-emitter: ^1.3.0 || ^2.0.0 + keycharm: ^0.2.0 || ^0.3.0 || ^0.4.0 + uuid: ^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^13.0.0 + vis-data: '>=8.0.0' + vis-util: '>=6.0.0' + + vis-util@6.0.0: + resolution: {integrity: sha512-qtpts3HRma0zPe4bO7t9A2uejkRNj8Z2Tb6do6lN85iPNWExFkUiVhdAq5uLGIUqBFduyYeqWJKv/jMkxX0R5g==} + engines: {node: '>=8'} + peerDependencies: + '@egjs/hammerjs': ^2.0.0 + component-emitter: ^1.3.0 || ^2.0.0 + + vite@7.1.11: + resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 jiti: '>=1.21.0' - less: '*' + less: ^4.0.0 lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -8341,8 +8583,8 @@ packages: yaml: optional: true - vite@7.1.5: - resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==} + vite@7.1.12: + resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -8556,10 +8798,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - write-file-atomic@5.0.1: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -8664,25 +8902,26 @@ snapshots: '@aduh95/viz.js@3.4.0': {} - '@ai-sdk/gateway@1.0.21(zod@3.25.76)': + '@ai-sdk/gateway@2.0.1(zod@3.25.76)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.8(zod@3.25.76) + '@ai-sdk/provider-utils': 3.0.12(zod@3.25.76) + '@vercel/oidc': 3.0.3 zod: 3.25.76 - '@ai-sdk/openai-compatible@1.0.15(zod@3.25.76)': + '@ai-sdk/openai-compatible@1.0.22(zod@3.25.76)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.8(zod@3.25.76) + '@ai-sdk/provider-utils': 3.0.12(zod@3.25.76) zod: 3.25.76 - '@ai-sdk/openai@2.0.28(zod@3.25.76)': + '@ai-sdk/openai@2.0.53(zod@3.25.76)': dependencies: '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.8(zod@3.25.76) + '@ai-sdk/provider-utils': 3.0.12(zod@3.25.76) zod: 3.25.76 - '@ai-sdk/provider-utils@3.0.8(zod@3.25.76)': + '@ai-sdk/provider-utils@3.0.12(zod@3.25.76)': dependencies: '@ai-sdk/provider': 2.0.0 '@standard-schema/spec': 1.0.0 @@ -8782,10 +9021,10 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@angular-builders/common@4.0.0(@types/node@22.18.6)(chokidar@4.0.3)(typescript@5.8.3)': + '@angular-builders/common@4.0.0(@types/node@24.9.2)(chokidar@4.0.3)(typescript@5.9.3)': dependencies: - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - ts-node: 10.9.2(@types/node@22.18.6)(typescript@5.8.3) + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) + ts-node: 10.9.2(@types/node@24.9.2)(typescript@5.9.3) tsconfig-paths: 4.2.0 transitivePeerDependencies: - '@swc/core' @@ -8794,17 +9033,17 @@ snapshots: - chokidar - typescript - '@angular-builders/jest@20.0.0(6c01f59db48b8ca6db50360b9422a4c0)': - dependencies: - '@angular-builders/common': 4.0.0(@types/node@22.18.6)(chokidar@4.0.3)(typescript@5.8.3) - '@angular-devkit/architect': 0.2003.2(chokidar@4.0.3) - '@angular-devkit/build-angular': 20.3.2(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@22.18.6)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3) - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - '@angular/compiler-cli': 20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser-dynamic': 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))) - jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - jest-preset-angular: 14.6.0(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(jsdom@20.0.3)(typescript@5.8.3) + '@angular-builders/jest@20.0.0(298286e299ccfff78b1834faa98544c9)': + dependencies: + '@angular-builders/common': 4.0.0(@types/node@24.9.2)(chokidar@4.0.3)(typescript@5.9.3) + '@angular-devkit/architect': 0.2003.8(chokidar@4.0.3) + '@angular-devkit/build-angular': 20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.9.2)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(jiti@1.21.7)(typescript@5.9.3) + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser-dynamic': 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))) + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + jest-preset-angular: 14.6.0(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(jsdom@20.0.3)(typescript@5.9.3) lodash: 4.17.21 transitivePeerDependencies: - '@babel/core' @@ -8822,21 +9061,28 @@ snapshots: - typescript - utf-8-validate - '@angular-devkit/architect@0.2003.2(chokidar@4.0.3)': + '@angular-devkit/architect@0.2003.7(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 20.3.7(chokidar@4.0.3) + rxjs: 7.8.2 + transitivePeerDependencies: + - chokidar + + '@angular-devkit/architect@0.2003.8(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) rxjs: 7.8.2 transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@20.3.2(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@22.18.6)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(jiti@1.21.7)(typescript@5.8.3)': + '@angular-devkit/build-angular@20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.9.2)(chokidar@4.0.3)(jest-environment-jsdom@29.7.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(jiti@1.21.7)(typescript@5.9.3)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2003.2(chokidar@4.0.3) - '@angular-devkit/build-webpack': 0.2003.2(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.101.2(esbuild@0.25.9)))(webpack@5.101.2(esbuild@0.25.9)) - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - '@angular/build': 20.3.2(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@22.18.6)(chokidar@4.0.3)(jiti@1.21.7)(less@4.4.0)(postcss@8.5.6)(terser@5.43.1)(tslib@2.8.1)(typescript@5.8.3) - '@angular/compiler-cli': 20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3) + '@angular-devkit/architect': 0.2003.7(chokidar@4.0.3) + '@angular-devkit/build-webpack': 0.2003.7(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.101.2(esbuild@0.25.9)))(webpack@5.101.2(esbuild@0.25.9)) + '@angular-devkit/core': 20.3.7(chokidar@4.0.3) + '@angular/build': 20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.9.2)(chokidar@4.0.3)(jiti@1.21.7)(less@4.4.0)(postcss@8.5.6)(terser@5.43.1)(tslib@2.8.1)(typescript@5.9.3) + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3) '@babel/core': 7.28.3 '@babel/generator': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 @@ -8847,11 +9093,11 @@ snapshots: '@babel/preset-env': 7.28.3(@babel/core@7.28.3) '@babel/runtime': 7.28.3 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 20.3.2(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9)) + '@ngtools/webpack': 20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(typescript@5.9.3)(webpack@5.101.2(esbuild@0.25.9)) ansi-colors: 4.1.3 autoprefixer: 10.4.21(postcss@8.5.6) babel-loader: 10.0.0(@babel/core@7.28.3)(webpack@5.101.2(esbuild@0.25.9)) - browserslist: 4.26.2 + browserslist: 4.27.0 copy-webpack-plugin: 13.0.1(webpack@5.101.2(esbuild@0.25.9)) css-loader: 7.1.2(webpack@5.101.2(esbuild@0.25.9)) esbuild-wasm: 0.25.9 @@ -8870,7 +9116,7 @@ snapshots: picomatch: 4.0.3 piscina: 5.1.3 postcss: 8.5.6 - postcss-loader: 8.1.1(postcss@8.5.6)(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9)) + postcss-loader: 8.1.1(postcss@8.5.6)(typescript@5.9.3)(webpack@5.101.2(esbuild@0.25.9)) resolve-url-loader: 5.0.0 rxjs: 7.8.2 sass: 1.90.0 @@ -8881,17 +9127,17 @@ snapshots: terser: 5.43.1 tree-kill: 1.2.2 tslib: 2.8.1 - typescript: 5.8.3 + typescript: 5.9.3 webpack: 5.101.2(esbuild@0.25.9) webpack-dev-middleware: 7.4.2(webpack@5.101.2(esbuild@0.25.9)) webpack-dev-server: 5.2.2(webpack@5.101.2(esbuild@0.25.9)) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.101.2(esbuild@0.25.9)) optionalDependencies: - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) esbuild: 0.25.9 - jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) jest-environment-jsdom: 29.7.0 transitivePeerDependencies: - '@angular/compiler' @@ -8916,9 +9162,9 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-webpack@0.2003.2(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.101.2(esbuild@0.25.9)))(webpack@5.101.2(esbuild@0.25.9))': + '@angular-devkit/build-webpack@0.2003.7(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.101.2(esbuild@0.25.9)))(webpack@5.101.2(esbuild@0.25.9))': dependencies: - '@angular-devkit/architect': 0.2003.2(chokidar@4.0.3) + '@angular-devkit/architect': 0.2003.7(chokidar@4.0.3) rxjs: 7.8.2 webpack: 5.101.2(esbuild@0.25.9) webpack-dev-server: 5.2.2(webpack@5.101.2(esbuild@0.25.9)) @@ -8947,7 +9193,18 @@ snapshots: optionalDependencies: chokidar: 4.0.3 - '@angular-devkit/core@20.2.2(chokidar@4.0.3)': + '@angular-devkit/core@20.3.4(chokidar@4.0.3)': + dependencies: + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + jsonc-parser: 3.3.1 + picomatch: 4.0.3 + rxjs: 7.8.2 + source-map: 0.7.6 + optionalDependencies: + chokidar: 4.0.3 + + '@angular-devkit/core@20.3.7(chokidar@4.0.3)': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) @@ -8958,7 +9215,7 @@ snapshots: optionalDependencies: chokidar: 4.0.3 - '@angular-devkit/core@20.3.2(chokidar@4.0.3)': + '@angular-devkit/core@20.3.8(chokidar@4.0.3)': dependencies: ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) @@ -8969,11 +9226,11 @@ snapshots: optionalDependencies: chokidar: 4.0.3 - '@angular-devkit/schematics-cli@19.2.15(@types/node@22.18.6)(chokidar@4.0.3)': + '@angular-devkit/schematics-cli@19.2.15(@types/node@24.9.2)(chokidar@4.0.3)': dependencies: '@angular-devkit/core': 19.2.15(chokidar@4.0.3) '@angular-devkit/schematics': 19.2.15(chokidar@4.0.3) - '@inquirer/prompts': 7.3.2(@types/node@22.18.6) + '@inquirer/prompts': 7.3.2(@types/node@24.9.2) ansi-colors: 4.1.3 symbol-observable: 4.0.0 yargs-parser: 21.1.1 @@ -9001,9 +9258,9 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/schematics@20.2.2(chokidar@4.0.3)': + '@angular-devkit/schematics@20.3.4(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 20.2.2(chokidar@4.0.3) + '@angular-devkit/core': 20.3.4(chokidar@4.0.3) jsonc-parser: 3.3.1 magic-string: 0.30.17 ora: 8.2.0 @@ -9011,9 +9268,9 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/schematics@20.3.2(chokidar@4.0.3)': + '@angular-devkit/schematics@20.3.7(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) + '@angular-devkit/core': 20.3.7(chokidar@4.0.3) jsonc-parser: 3.3.1 magic-string: 0.30.17 ora: 8.2.0 @@ -9021,95 +9278,56 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-eslint/builder@20.2.0(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@angular-devkit/schematics@20.3.8(chokidar@4.0.3)': dependencies: - '@angular-devkit/architect': 0.2003.2(chokidar@4.0.3) - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) + jsonc-parser: 3.3.1 + magic-string: 0.30.17 + ora: 8.2.0 + rxjs: 7.8.2 transitivePeerDependencies: - chokidar - '@angular-eslint/builder@20.3.0(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@angular-eslint/builder@20.5.0(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@angular-devkit/architect': 0.2003.2(chokidar@4.0.3) - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + '@angular-devkit/architect': 0.2003.8(chokidar@4.0.3) + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 transitivePeerDependencies: - chokidar - '@angular-eslint/bundled-angular-compiler@20.2.0': {} - - '@angular-eslint/bundled-angular-compiler@20.3.0': {} - - '@angular-eslint/eslint-plugin-template@20.2.0(@angular-eslint/template-parser@20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.2.0 - '@angular-eslint/template-parser': 20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/utils': 20.2.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - aria-query: 5.3.2 - axobject-query: 4.1.0 - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + '@angular-eslint/bundled-angular-compiler@20.5.0': {} - '@angular-eslint/eslint-plugin-template@20.3.0(@angular-eslint/template-parser@20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@angular-eslint/eslint-plugin-template@20.5.0(@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/types@8.46.2)(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@angular-eslint/bundled-angular-compiler': 20.3.0 - '@angular-eslint/template-parser': 20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/utils': 20.3.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + '@angular-eslint/bundled-angular-compiler': 20.5.0 + '@angular-eslint/template-parser': 20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@angular-eslint/utils': 20.5.0(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) aria-query: 5.3.2 axobject-query: 4.1.0 - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 - - '@angular-eslint/eslint-plugin@20.2.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.2.0 - '@angular-eslint/utils': 20.2.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 - '@angular-eslint/eslint-plugin@20.3.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@angular-eslint/eslint-plugin@20.5.0(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@angular-eslint/bundled-angular-compiler': 20.3.0 - '@angular-eslint/utils': 20.3.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 - - '@angular-eslint/schematics@20.2.0(@angular-eslint/template-parser@20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': - dependencies: - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - '@angular-devkit/schematics': 20.3.2(chokidar@4.0.3) - '@angular-eslint/eslint-plugin': 20.2.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/eslint-plugin-template': 20.2.0(@angular-eslint/template-parser@20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - ignore: 7.0.5 - semver: 7.7.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - '@angular-eslint/template-parser' - - '@typescript-eslint/types' - - '@typescript-eslint/utils' - - chokidar - - eslint - - typescript + '@angular-eslint/bundled-angular-compiler': 20.5.0 + '@angular-eslint/utils': 20.5.0(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 - '@angular-eslint/schematics@20.3.0(@angular-eslint/template-parser@20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@angular-eslint/schematics@20.5.0(@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/types@8.46.2)(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - '@angular-devkit/schematics': 20.3.2(chokidar@4.0.3) - '@angular-eslint/eslint-plugin': 20.3.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/eslint-plugin-template': 20.3.0(@angular-eslint/template-parser@20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) + '@angular-devkit/schematics': 20.3.8(chokidar@4.0.3) + '@angular-eslint/eslint-plugin': 20.5.0(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@angular-eslint/eslint-plugin-template': 20.5.0(@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/types@8.46.2)(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) ignore: 7.0.5 - semver: 7.7.2 + semver: 7.7.3 strip-json-comments: 3.1.1 transitivePeerDependencies: - '@angular-eslint/template-parser' @@ -9119,52 +9337,38 @@ snapshots: - eslint - typescript - '@angular-eslint/template-parser@20.2.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.2.0 - eslint: 9.36.0(jiti@1.21.7) - eslint-scope: 8.4.0 - typescript: 5.8.3 - - '@angular-eslint/template-parser@20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@angular-eslint/bundled-angular-compiler': 20.3.0 - eslint: 9.36.0(jiti@1.21.7) + '@angular-eslint/bundled-angular-compiler': 20.5.0 + eslint: 9.39.0(jiti@1.21.7) eslint-scope: 8.4.0 - typescript: 5.8.3 - - '@angular-eslint/utils@20.2.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': - dependencies: - '@angular-eslint/bundled-angular-compiler': 20.2.0 - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + typescript: 5.9.3 - '@angular-eslint/utils@20.3.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@angular-eslint/utils@20.5.0(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@angular-eslint/bundled-angular-compiler': 20.3.0 - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + '@angular-eslint/bundled-angular-compiler': 20.5.0 + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 - '@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))': + '@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) tslib: 2.8.1 - '@angular/build@20.3.2(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@22.18.6)(chokidar@4.0.3)(jiti@1.21.7)(less@4.4.0)(postcss@8.5.6)(terser@5.43.1)(tslib@2.8.1)(typescript@5.8.3)': + '@angular/build@20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@types/node@24.9.2)(chokidar@4.0.3)(jiti@1.21.7)(less@4.4.0)(postcss@8.5.6)(terser@5.43.1)(tslib@2.8.1)(typescript@5.9.3)': dependencies: '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2003.2(chokidar@4.0.3) - '@angular/compiler': 20.3.1 - '@angular/compiler-cli': 20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3) + '@angular-devkit/architect': 0.2003.7(chokidar@4.0.3) + '@angular/compiler': 20.3.7 + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3) '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.14(@types/node@22.18.6) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.1.5(@types/node@22.18.6)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)) + '@inquirer/confirm': 5.1.14(@types/node@24.9.2) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.1.11(@types/node@24.9.2)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1)) beasties: 0.3.5 - browserslist: 4.26.2 + browserslist: 4.27.0 esbuild: 0.25.9 https-proxy-agent: 7.0.6 istanbul-lib-instrument: 6.0.3 @@ -9175,18 +9379,18 @@ snapshots: parse5-html-rewriting-stream: 8.0.0 picomatch: 4.0.3 piscina: 5.1.3 - rolldown: 1.0.0-beta.32 + rollup: 4.52.3 sass: 1.90.0 semver: 7.7.2 source-map-support: 0.5.21 tinyglobby: 0.2.14 tslib: 2.8.1 - typescript: 5.8.3 - vite: 7.1.5(@types/node@22.18.6)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1) + typescript: 5.9.3 + vite: 7.1.11(@types/node@24.9.2)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1) watchpack: 2.4.4 optionalDependencies: - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) less: 4.4.0 lmdb: 3.4.2 postcss: 8.5.6 @@ -9203,23 +9407,23 @@ snapshots: - tsx - yaml - '@angular/cdk@20.0.2(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': + '@angular/cdk@20.2.10(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - parse5: 7.3.0 + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + parse5: 8.0.0 rxjs: 7.8.2 tslib: 2.8.1 - '@angular/cli@20.3.2(@types/node@22.18.6)(chokidar@4.0.3)': + '@angular/cli@20.3.7(@types/node@24.9.2)(chokidar@4.0.3)': dependencies: - '@angular-devkit/architect': 0.2003.2(chokidar@4.0.3) - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - '@angular-devkit/schematics': 20.3.2(chokidar@4.0.3) - '@inquirer/prompts': 7.8.2(@types/node@22.18.6) - '@listr2/prompt-adapter-inquirer': 3.0.1(@inquirer/prompts@7.8.2(@types/node@22.18.6))(@types/node@22.18.6)(listr2@9.0.1) + '@angular-devkit/architect': 0.2003.7(chokidar@4.0.3) + '@angular-devkit/core': 20.3.7(chokidar@4.0.3) + '@angular-devkit/schematics': 20.3.7(chokidar@4.0.3) + '@inquirer/prompts': 7.8.2(@types/node@24.9.2) + '@listr2/prompt-adapter-inquirer': 3.0.1(@inquirer/prompts@7.8.2(@types/node@24.9.2))(@types/node@24.9.2)(listr2@9.0.1) '@modelcontextprotocol/sdk': 1.17.3 - '@schematics/angular': 20.3.2(chokidar@4.0.3) + '@schematics/angular': 20.3.7(chokidar@4.0.3) '@yarnpkg/lockfile': 1.1.0 algoliasearch: 5.35.0 ini: 5.0.0 @@ -9236,81 +9440,81 @@ snapshots: - chokidar - supports-color - '@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': + '@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2)': dependencies: - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3)': + '@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3)': dependencies: - '@angular/compiler': 20.3.1 + '@angular/compiler': 20.3.7 '@babel/core': 7.28.3 '@jridgewell/sourcemap-codec': 1.5.5 chokidar: 4.0.3 convert-source-map: 1.9.0 reflect-metadata: 0.2.2 - semver: 7.7.2 + semver: 7.7.3 tslib: 2.8.1 yargs: 18.0.0 optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@angular/compiler@20.3.1': + '@angular/compiler@20.3.7': dependencies: tslib: 2.8.1 - '@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)': + '@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)': dependencies: rxjs: 7.8.2 tslib: 2.8.1 optionalDependencies: - '@angular/compiler': 20.3.1 + '@angular/compiler': 20.3.7 zone.js: 0.15.1 - '@angular/forms@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': + '@angular/forms@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/language-service@20.3.1': {} + '@angular/language-service@20.3.9': {} - '@angular/material@20.0.2(2bbdcc961587c2d21a1f5fd45a68ee52)': + '@angular/material@20.2.10(72d1932aa29c0670c8359e3ed8a5ff55)': dependencies: - '@angular/cdk': 20.0.2(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/forms': 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) - '@angular/platform-browser': 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/cdk': 20.2.10(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/forms': 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) rxjs: 7.8.2 tslib: 2.8.1 - '@angular/platform-browser-dynamic@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))': + '@angular/platform-browser-dynamic@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))': dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/compiler': 20.3.1 - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/compiler': 20.3.7 + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) tslib: 2.8.1 - '@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))': + '@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) tslib: 2.8.1 optionalDependencies: - '@angular/animations': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/animations': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) - '@angular/router@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': + '@angular/router@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)': dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) rxjs: 7.8.2 tslib: 2.8.1 @@ -9322,20 +9526,20 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.4': {} + '@babel/compat-data@7.28.5': {} '@babel/core@7.28.3': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 convert-source-map: 2.0.0 debug: 4.4.3 gensync: 1.0.0-beta.2 @@ -9347,14 +9551,34 @@ snapshots: '@babel/core@7.28.4': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -9366,58 +9590,66 @@ snapshots: '@babel/generator@7.28.3': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.2 + browserslist: 4.27.0 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.3)': + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.3)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.4)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 @@ -9431,7 +9663,7 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.3 lodash.debounce: 4.0.8 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color @@ -9442,23 +9674,23 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.3 lodash.debounce: 4.0.8 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color '@babel/helper-globals@7.28.0': {} - '@babel/helper-member-expression-to-functions@7.27.1': + '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -9466,8 +9698,8 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9475,14 +9707,23 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-plugin-utils@7.27.1': {} @@ -9491,7 +9732,7 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9500,75 +9741,77 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-split-export-declaration@7.24.7': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/parser@7.28.4': + '@babel/parser@7.28.5': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9597,7 +9840,7 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.3) transitivePeerDependencies: - supports-color @@ -9606,7 +9849,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.4) transitivePeerDependencies: - supports-color @@ -9614,7 +9857,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9622,7 +9865,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9634,24 +9877,24 @@ snapshots: dependencies: '@babel/core': 7.28.4 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.4)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.4)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.3)': @@ -9674,76 +9917,81 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.4)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.4)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.4)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.4)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.3)': @@ -9761,7 +10009,7 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9770,7 +10018,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9802,12 +10050,12 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoping@7.28.4(@babel/core@7.28.3)': + '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoping@7.28.4(@babel/core@7.28.4)': + '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -9815,7 +10063,7 @@ snapshots: '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -9823,7 +10071,7 @@ snapshots: '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -9831,7 +10079,7 @@ snapshots: '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -9839,7 +10087,7 @@ snapshots: '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -9852,7 +10100,7 @@ snapshots: '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9864,7 +10112,7 @@ snapshots: '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -9880,32 +10128,32 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 '@babel/template': 7.27.2 - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.3)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.3)': @@ -9921,13 +10169,13 @@ snapshots: '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.3)': @@ -9944,7 +10192,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.3) transitivePeerDependencies: - supports-color @@ -9952,16 +10200,16 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -9997,7 +10245,7 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10006,7 +10254,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10030,12 +10278,12 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -10082,23 +10330,23 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10121,13 +10369,13 @@ snapshots: '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.3)': @@ -10165,9 +10413,9 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.3) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10176,9 +10424,9 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -10208,7 +10456,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.3)': + '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 @@ -10216,7 +10464,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -10237,7 +10485,7 @@ snapshots: '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10245,7 +10493,7 @@ snapshots: '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10254,7 +10502,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10263,7 +10511,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -10291,13 +10539,13 @@ snapshots: '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.3)': @@ -10391,47 +10639,47 @@ snapshots: '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/preset-env@7.28.3(@babel/core@7.28.3)': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.3 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.3) '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.3) '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.3) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.3) @@ -10444,28 +10692,28 @@ snapshots: '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.3) '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-block-scoping': 7.28.4(@babel/core@7.28.3) + '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.3) '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.3) '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.3) '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.3) '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.3) '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.3) '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.3) '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.3) @@ -10474,7 +10722,7 @@ snapshots: '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.3) '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.3) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.3) '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.3) @@ -10495,19 +10743,19 @@ snapshots: babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.3) babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.3) babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.3) - core-js-compat: 3.45.1 + core-js-compat: 3.46.0 semver: 6.3.1 transitivePeerDependencies: - supports-color '@babel/preset-env@7.28.3(@babel/core@7.28.4)': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.4) '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.4) '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.4) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.4) @@ -10520,28 +10768,28 @@ snapshots: '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.4) '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-block-scoping': 7.28.4(@babel/core@7.28.4) + '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.4) '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.4) '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.4) @@ -10550,7 +10798,7 @@ snapshots: '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.4) '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.4) @@ -10571,7 +10819,7 @@ snapshots: babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.4) babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.4) babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.45.1 + core-js-compat: 3.46.0 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -10580,14 +10828,14 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 esutils: 2.0.3 '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 esutils: 2.0.3 '@babel/runtime@7.28.3': {} @@ -10597,17 +10845,17 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 - '@babel/traverse@7.28.4': + '@babel/traverse@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -10617,16 +10865,25 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@0.2.3': {} '@borewit/text-codec@0.1.1': {} + '@cacheable/utils@2.1.0': + dependencies: + keyv: 5.5.3 + '@colors/colors@1.5.0': optional: true - '@compodoc/compodoc@1.1.30(typescript@5.8.3)': + '@compodoc/compodoc@1.1.32(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)(keycharm@0.2.0)(typescript@5.9.3)(vis-data@8.0.3(uuid@11.1.0)(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)))(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1))': dependencies: - '@angular-devkit/schematics': 20.2.2(chokidar@4.0.3) + '@angular-devkit/schematics': 20.3.4(chokidar@4.0.3) '@babel/core': 7.28.4 '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.4) '@babel/preset-env': 7.28.3(@babel/core@7.28.4) @@ -10638,8 +10895,8 @@ snapshots: cheerio: 1.1.2 chokidar: 4.0.3 colors: 1.4.0 - commander: 14.0.1 - cosmiconfig: 9.0.0(typescript@5.8.3) + commander: 14.0.2 + cosmiconfig: 9.0.0(typescript@5.9.3) decache: 4.6.2 es6-shim: 0.35.8 fancy-log: 2.0.0 @@ -10648,7 +10905,7 @@ snapshots: glob: 11.0.3 handlebars: 4.7.8 html-entities: 2.6.0 - i18next: 25.5.2(typescript@5.8.3) + i18next: 25.5.3(typescript@5.9.3) json5: 2.2.3 lodash: 4.17.21 loglevel: 1.9.2 @@ -10662,16 +10919,21 @@ snapshots: picocolors: 1.1.1 polka: 0.5.2 prismjs: 1.30.0 - semver: 7.7.2 + semver: 7.7.3 sirv: 3.0.2 svg-pan-zoom: 3.6.2 tablesort: 5.6.0 - ts-morph: 26.0.0 + ts-morph: 27.0.2 uuid: 11.1.0 - vis: 4.21.0-EOL + vis-network: 10.0.2(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)(keycharm@0.2.0)(uuid@11.1.0)(vis-data@8.0.3(uuid@11.1.0)(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)))(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)) transitivePeerDependencies: + - '@egjs/hammerjs' + - component-emitter + - keycharm - supports-color - typescript + - vis-data + - vis-util '@compodoc/live-server@1.2.3': dependencies: @@ -10696,7 +10958,7 @@ snapshots: dependencies: ansi-colors: 4.1.3 fancy-log: 2.0.0 - typescript: 5.8.3 + typescript: 5.9.3 '@compodoc/ngd-transformer@2.1.3': dependencies: @@ -10711,6 +10973,10 @@ snapshots: '@discoveryjs/json-ext@0.6.3': {} + '@egjs/hammerjs@2.0.17': + dependencies: + '@types/hammerjs': 2.0.46 + '@emnapi/core@1.5.0': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -10727,190 +10993,268 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.10': + '@esbuild/aix-ppc64@0.25.11': + optional: true + + '@esbuild/aix-ppc64@0.25.12': optional: true '@esbuild/aix-ppc64@0.25.9': optional: true - '@esbuild/android-arm64@0.25.10': + '@esbuild/android-arm64@0.25.11': + optional: true + + '@esbuild/android-arm64@0.25.12': optional: true '@esbuild/android-arm64@0.25.9': optional: true - '@esbuild/android-arm@0.25.10': + '@esbuild/android-arm@0.25.11': + optional: true + + '@esbuild/android-arm@0.25.12': optional: true '@esbuild/android-arm@0.25.9': optional: true - '@esbuild/android-x64@0.25.10': + '@esbuild/android-x64@0.25.11': + optional: true + + '@esbuild/android-x64@0.25.12': optional: true '@esbuild/android-x64@0.25.9': optional: true - '@esbuild/darwin-arm64@0.25.10': + '@esbuild/darwin-arm64@0.25.11': + optional: true + + '@esbuild/darwin-arm64@0.25.12': optional: true '@esbuild/darwin-arm64@0.25.9': optional: true - '@esbuild/darwin-x64@0.25.10': + '@esbuild/darwin-x64@0.25.11': + optional: true + + '@esbuild/darwin-x64@0.25.12': optional: true '@esbuild/darwin-x64@0.25.9': optional: true - '@esbuild/freebsd-arm64@0.25.10': + '@esbuild/freebsd-arm64@0.25.11': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': optional: true '@esbuild/freebsd-arm64@0.25.9': optional: true - '@esbuild/freebsd-x64@0.25.10': + '@esbuild/freebsd-x64@0.25.11': + optional: true + + '@esbuild/freebsd-x64@0.25.12': optional: true '@esbuild/freebsd-x64@0.25.9': optional: true - '@esbuild/linux-arm64@0.25.10': + '@esbuild/linux-arm64@0.25.11': + optional: true + + '@esbuild/linux-arm64@0.25.12': optional: true '@esbuild/linux-arm64@0.25.9': optional: true - '@esbuild/linux-arm@0.25.10': + '@esbuild/linux-arm@0.25.11': + optional: true + + '@esbuild/linux-arm@0.25.12': optional: true '@esbuild/linux-arm@0.25.9': optional: true - '@esbuild/linux-ia32@0.25.10': + '@esbuild/linux-ia32@0.25.11': + optional: true + + '@esbuild/linux-ia32@0.25.12': optional: true '@esbuild/linux-ia32@0.25.9': optional: true - '@esbuild/linux-loong64@0.25.10': + '@esbuild/linux-loong64@0.25.11': + optional: true + + '@esbuild/linux-loong64@0.25.12': optional: true '@esbuild/linux-loong64@0.25.9': optional: true - '@esbuild/linux-mips64el@0.25.10': + '@esbuild/linux-mips64el@0.25.11': + optional: true + + '@esbuild/linux-mips64el@0.25.12': optional: true '@esbuild/linux-mips64el@0.25.9': optional: true - '@esbuild/linux-ppc64@0.25.10': + '@esbuild/linux-ppc64@0.25.11': + optional: true + + '@esbuild/linux-ppc64@0.25.12': optional: true '@esbuild/linux-ppc64@0.25.9': optional: true - '@esbuild/linux-riscv64@0.25.10': + '@esbuild/linux-riscv64@0.25.11': + optional: true + + '@esbuild/linux-riscv64@0.25.12': optional: true '@esbuild/linux-riscv64@0.25.9': optional: true - '@esbuild/linux-s390x@0.25.10': + '@esbuild/linux-s390x@0.25.11': + optional: true + + '@esbuild/linux-s390x@0.25.12': optional: true '@esbuild/linux-s390x@0.25.9': optional: true - '@esbuild/linux-x64@0.25.10': + '@esbuild/linux-x64@0.25.11': + optional: true + + '@esbuild/linux-x64@0.25.12': optional: true '@esbuild/linux-x64@0.25.9': optional: true - '@esbuild/netbsd-arm64@0.25.10': + '@esbuild/netbsd-arm64@0.25.11': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': optional: true '@esbuild/netbsd-arm64@0.25.9': optional: true - '@esbuild/netbsd-x64@0.25.10': + '@esbuild/netbsd-x64@0.25.11': + optional: true + + '@esbuild/netbsd-x64@0.25.12': optional: true '@esbuild/netbsd-x64@0.25.9': optional: true - '@esbuild/openbsd-arm64@0.25.10': + '@esbuild/openbsd-arm64@0.25.11': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': optional: true '@esbuild/openbsd-arm64@0.25.9': optional: true - '@esbuild/openbsd-x64@0.25.10': + '@esbuild/openbsd-x64@0.25.11': + optional: true + + '@esbuild/openbsd-x64@0.25.12': optional: true '@esbuild/openbsd-x64@0.25.9': optional: true - '@esbuild/openharmony-arm64@0.25.10': + '@esbuild/openharmony-arm64@0.25.11': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': optional: true '@esbuild/openharmony-arm64@0.25.9': optional: true - '@esbuild/sunos-x64@0.25.10': + '@esbuild/sunos-x64@0.25.11': + optional: true + + '@esbuild/sunos-x64@0.25.12': optional: true '@esbuild/sunos-x64@0.25.9': optional: true - '@esbuild/win32-arm64@0.25.10': + '@esbuild/win32-arm64@0.25.11': + optional: true + + '@esbuild/win32-arm64@0.25.12': optional: true '@esbuild/win32-arm64@0.25.9': optional: true - '@esbuild/win32-ia32@0.25.10': + '@esbuild/win32-ia32@0.25.11': + optional: true + + '@esbuild/win32-ia32@0.25.12': optional: true '@esbuild/win32-ia32@0.25.9': optional: true - '@esbuild/win32-x64@0.25.10': + '@esbuild/win32-x64@0.25.11': + optional: true + + '@esbuild/win32-x64@0.25.12': optional: true '@esbuild/win32-x64@0.25.9': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.36.0(jiti@1.21.7))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.0(jiti@1.21.7))': dependencies: - eslint: 9.36.0(jiti@1.21.7) + eslint: 9.39.0(jiti@1.21.7) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.4.0(eslint@9.36.0(jiti@1.21.7))': + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/compat@1.4.1(eslint@9.39.0(jiti@1.21.7))': dependencies: - '@eslint/core': 0.16.0 + '@eslint/core': 0.17.0 optionalDependencies: - eslint: 9.36.0(jiti@1.21.7) + eslint: 9.39.0(jiti@1.21.7) - '@eslint/config-array@0.21.0': + '@eslint/config-array@0.21.1': dependencies: - '@eslint/object-schema': 2.1.6 + '@eslint/object-schema': 2.1.7 debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.3.1': {} - - '@eslint/core@0.15.2': + '@eslint/config-helpers@0.4.2': dependencies: - '@types/json-schema': 7.0.15 + '@eslint/core': 0.17.0 - '@eslint/core@0.16.0': + '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 @@ -10928,18 +11272,18 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.36.0': {} + '@eslint/js@9.39.0': {} - '@eslint/object-schema@2.1.6': {} + '@eslint/object-schema@2.1.7': {} - '@eslint/plugin-kit@0.3.5': + '@eslint/plugin-kit@0.4.1': dependencies: - '@eslint/core': 0.15.2 + '@eslint/core': 0.17.0 levn: 0.4.1 - '@fortawesome/angular-fontawesome@2.0.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))': + '@fortawesome/angular-fontawesome@2.0.1(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) '@fortawesome/fontawesome-svg-core': 6.7.2 tslib: 2.8.1 @@ -10957,7 +11301,7 @@ snapshots: dependencies: '@fortawesome/fontawesome-common-types': 6.7.2 - '@golevelup/ts-jest@0.6.2': {} + '@golevelup/ts-jest@0.7.0': {} '@humanfs/core@0.19.1': {} @@ -10970,167 +11314,167 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/ansi@1.0.0': {} + '@inquirer/ansi@1.0.1': {} - '@inquirer/checkbox@4.2.4(@types/node@22.18.6)': + '@inquirer/checkbox@4.3.0(@types/node@24.9.2)': dependencies: - '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/ansi': 1.0.1 + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9(@types/node@24.9.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/confirm@5.1.14(@types/node@22.18.6)': + '@inquirer/confirm@5.1.14(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/confirm@5.1.18(@types/node@22.18.6)': + '@inquirer/confirm@5.1.19(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/core@10.2.2(@types/node@22.18.6)': + '@inquirer/core@10.3.0(@types/node@24.9.2)': dependencies: - '@inquirer/ansi': 1.0.0 - '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/ansi': 1.0.1 + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9(@types/node@24.9.2) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/editor@4.2.20(@types/node@22.18.6)': + '@inquirer/editor@4.2.21(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/external-editor': 1.0.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/external-editor': 1.0.2(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/expand@4.0.20(@types/node@22.18.6)': + '@inquirer/expand@4.0.21(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/external-editor@1.0.2(@types/node@22.18.6)': + '@inquirer/external-editor@1.0.2(@types/node@24.9.2)': dependencies: chardet: 2.1.0 iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/figures@1.0.13': {} + '@inquirer/figures@1.0.14': {} - '@inquirer/input@4.2.4(@types/node@22.18.6)': + '@inquirer/input@4.2.5(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/number@3.0.20(@types/node@22.18.6)': + '@inquirer/number@3.0.21(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/password@4.0.20(@types/node@22.18.6)': + '@inquirer/password@4.0.21(@types/node@24.9.2)': dependencies: - '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/ansi': 1.0.1 + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 - - '@inquirer/prompts@7.3.2(@types/node@22.18.6)': - dependencies: - '@inquirer/checkbox': 4.2.4(@types/node@22.18.6) - '@inquirer/confirm': 5.1.18(@types/node@22.18.6) - '@inquirer/editor': 4.2.20(@types/node@22.18.6) - '@inquirer/expand': 4.0.20(@types/node@22.18.6) - '@inquirer/input': 4.2.4(@types/node@22.18.6) - '@inquirer/number': 3.0.20(@types/node@22.18.6) - '@inquirer/password': 4.0.20(@types/node@22.18.6) - '@inquirer/rawlist': 4.1.8(@types/node@22.18.6) - '@inquirer/search': 3.1.3(@types/node@22.18.6) - '@inquirer/select': 4.3.4(@types/node@22.18.6) + '@types/node': 24.9.2 + + '@inquirer/prompts@7.3.2(@types/node@24.9.2)': + dependencies: + '@inquirer/checkbox': 4.3.0(@types/node@24.9.2) + '@inquirer/confirm': 5.1.19(@types/node@24.9.2) + '@inquirer/editor': 4.2.21(@types/node@24.9.2) + '@inquirer/expand': 4.0.21(@types/node@24.9.2) + '@inquirer/input': 4.2.5(@types/node@24.9.2) + '@inquirer/number': 3.0.21(@types/node@24.9.2) + '@inquirer/password': 4.0.21(@types/node@24.9.2) + '@inquirer/rawlist': 4.1.9(@types/node@24.9.2) + '@inquirer/search': 3.2.0(@types/node@24.9.2) + '@inquirer/select': 4.4.0(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 - - '@inquirer/prompts@7.8.0(@types/node@22.18.6)': - dependencies: - '@inquirer/checkbox': 4.2.4(@types/node@22.18.6) - '@inquirer/confirm': 5.1.18(@types/node@22.18.6) - '@inquirer/editor': 4.2.20(@types/node@22.18.6) - '@inquirer/expand': 4.0.20(@types/node@22.18.6) - '@inquirer/input': 4.2.4(@types/node@22.18.6) - '@inquirer/number': 3.0.20(@types/node@22.18.6) - '@inquirer/password': 4.0.20(@types/node@22.18.6) - '@inquirer/rawlist': 4.1.8(@types/node@22.18.6) - '@inquirer/search': 3.1.3(@types/node@22.18.6) - '@inquirer/select': 4.3.4(@types/node@22.18.6) + '@types/node': 24.9.2 + + '@inquirer/prompts@7.8.0(@types/node@24.9.2)': + dependencies: + '@inquirer/checkbox': 4.3.0(@types/node@24.9.2) + '@inquirer/confirm': 5.1.19(@types/node@24.9.2) + '@inquirer/editor': 4.2.21(@types/node@24.9.2) + '@inquirer/expand': 4.0.21(@types/node@24.9.2) + '@inquirer/input': 4.2.5(@types/node@24.9.2) + '@inquirer/number': 3.0.21(@types/node@24.9.2) + '@inquirer/password': 4.0.21(@types/node@24.9.2) + '@inquirer/rawlist': 4.1.9(@types/node@24.9.2) + '@inquirer/search': 3.2.0(@types/node@24.9.2) + '@inquirer/select': 4.4.0(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 - - '@inquirer/prompts@7.8.2(@types/node@22.18.6)': - dependencies: - '@inquirer/checkbox': 4.2.4(@types/node@22.18.6) - '@inquirer/confirm': 5.1.18(@types/node@22.18.6) - '@inquirer/editor': 4.2.20(@types/node@22.18.6) - '@inquirer/expand': 4.0.20(@types/node@22.18.6) - '@inquirer/input': 4.2.4(@types/node@22.18.6) - '@inquirer/number': 3.0.20(@types/node@22.18.6) - '@inquirer/password': 4.0.20(@types/node@22.18.6) - '@inquirer/rawlist': 4.1.8(@types/node@22.18.6) - '@inquirer/search': 3.1.3(@types/node@22.18.6) - '@inquirer/select': 4.3.4(@types/node@22.18.6) + '@types/node': 24.9.2 + + '@inquirer/prompts@7.8.2(@types/node@24.9.2)': + dependencies: + '@inquirer/checkbox': 4.3.0(@types/node@24.9.2) + '@inquirer/confirm': 5.1.19(@types/node@24.9.2) + '@inquirer/editor': 4.2.21(@types/node@24.9.2) + '@inquirer/expand': 4.0.21(@types/node@24.9.2) + '@inquirer/input': 4.2.5(@types/node@24.9.2) + '@inquirer/number': 3.0.21(@types/node@24.9.2) + '@inquirer/password': 4.0.21(@types/node@24.9.2) + '@inquirer/rawlist': 4.1.9(@types/node@24.9.2) + '@inquirer/search': 3.2.0(@types/node@24.9.2) + '@inquirer/select': 4.4.0(@types/node@24.9.2) optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/rawlist@4.1.8(@types/node@22.18.6)': + '@inquirer/rawlist@4.1.9(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/search@3.1.3(@types/node@22.18.6)': + '@inquirer/search@3.2.0(@types/node@24.9.2)': dependencies: - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9(@types/node@24.9.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/select@4.3.4(@types/node@22.18.6)': + '@inquirer/select@4.4.0(@types/node@24.9.2)': dependencies: - '@inquirer/ansi': 1.0.0 - '@inquirer/core': 10.2.2(@types/node@22.18.6) - '@inquirer/figures': 1.0.13 - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/ansi': 1.0.1 + '@inquirer/core': 10.3.0(@types/node@24.9.2) + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9(@types/node@24.9.2) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@inquirer/type@3.0.8(@types/node@22.18.6)': + '@inquirer/type@3.0.9(@types/node@24.9.2)': optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@isaacs/balanced-match@4.0.1': {} @@ -11161,85 +11505,86 @@ snapshots: '@istanbuljs/schema@0.1.3': {} - '@jest/console@29.7.0': + '@jest/console@30.2.0': dependencies: - '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 + jest-message-util: 30.2.0 + jest-util: 30.2.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3))': + '@jest/core@30.2.0(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3))': dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@jest/console': 30.2.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.2.0 + '@jest/test-result': 30.2.0 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 ansi-escapes: 4.3.2 chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 + ci-info: 4.3.1 + exit-x: 0.2.2 graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 + jest-changed-files: 30.2.0 + jest-config: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + jest-haste-map: 30.2.0 + jest-message-util: 30.2.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.2.0 + jest-resolve-dependencies: 30.2.0 + jest-runner: 30.2.0 + jest-runtime: 30.2.0 + jest-snapshot: 30.2.0 + jest-util: 30.2.0 + jest-validate: 30.2.0 + jest-watcher: 30.2.0 micromatch: 4.0.8 - pretty-format: 29.7.0 + pretty-format: 30.2.0 slash: 3.0.0 - strip-ansi: 6.0.1 transitivePeerDependencies: - babel-plugin-macros + - esbuild-register - supports-color - ts-node '@jest/diff-sequences@30.0.1': {} + '@jest/environment-jsdom-abstract@30.2.0(jsdom@20.0.3)': + dependencies: + '@jest/environment': 30.2.0 + '@jest/fake-timers': 30.2.0 + '@jest/types': 30.2.0 + '@types/jsdom': 21.1.7 + '@types/node': 24.9.2 + jest-mock: 30.2.0 + jest-util: 30.2.0 + jsdom: 20.0.3 + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@types/node': 24.9.2 jest-mock: 29.7.0 - '@jest/environment@30.1.2': - dependencies: - '@jest/fake-timers': 30.1.2 - '@jest/types': 30.0.5 - '@types/node': 22.18.6 - jest-mock: 30.0.5 - - '@jest/expect-utils@29.7.0': + '@jest/environment@30.2.0': dependencies: - jest-get-type: 29.6.3 + '@jest/fake-timers': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 + jest-mock: 30.2.0 - '@jest/expect-utils@30.1.2': + '@jest/expect-utils@30.2.0': dependencies: '@jest/get-type': 30.1.0 - '@jest/expect@29.7.0': - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - - '@jest/expect@30.1.2': + '@jest/expect@30.2.0': dependencies: - expect: 30.1.2 - jest-snapshot: 30.1.2 + expect: 30.2.0 + jest-snapshot: 30.2.0 transitivePeerDependencies: - supports-color @@ -11247,70 +11592,60 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 22.18.6 + '@types/node': 24.9.2 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 - '@jest/fake-timers@30.1.2': + '@jest/fake-timers@30.2.0': dependencies: - '@jest/types': 30.0.5 + '@jest/types': 30.2.0 '@sinonjs/fake-timers': 13.0.5 - '@types/node': 22.18.6 - jest-message-util: 30.1.0 - jest-mock: 30.0.5 - jest-util: 30.0.5 + '@types/node': 24.9.2 + jest-message-util: 30.2.0 + jest-mock: 30.2.0 + jest-util: 30.2.0 '@jest/get-type@30.1.0': {} - '@jest/globals@29.7.0': - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 - transitivePeerDependencies: - - supports-color - - '@jest/globals@30.1.2': + '@jest/globals@30.2.0': dependencies: - '@jest/environment': 30.1.2 - '@jest/expect': 30.1.2 - '@jest/types': 30.0.5 - jest-mock: 30.0.5 + '@jest/environment': 30.2.0 + '@jest/expect': 30.2.0 + '@jest/types': 30.2.0 + jest-mock: 30.2.0 transitivePeerDependencies: - supports-color '@jest/pattern@30.0.1': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 jest-regex-util: 30.0.1 - '@jest/reporters@29.7.0': + '@jest/reporters@30.2.0': dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.2.0 + '@jest/test-result': 30.2.0 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 22.18.6 + '@types/node': 24.9.2 chalk: 4.1.2 - collect-v8-coverage: 1.0.2 - exit: 0.1.2 - glob: 7.2.3 + collect-v8-coverage: 1.0.3 + exit-x: 0.2.2 + glob: 10.4.5 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 + istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 + jest-message-util: 30.2.0 + jest-util: 30.2.0 + jest-worker: 30.2.0 slash: 3.0.0 string-length: 4.0.2 - strip-ansi: 6.0.1 v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color @@ -11323,66 +11658,46 @@ snapshots: dependencies: '@sinclair/typebox': 0.34.41 - '@jest/snapshot-utils@30.1.2': + '@jest/snapshot-utils@30.2.0': dependencies: - '@jest/types': 30.0.5 + '@jest/types': 30.2.0 chalk: 4.1.2 graceful-fs: 4.2.11 natural-compare: 1.4.0 - '@jest/source-map@29.6.3': + '@jest/source-map@30.0.1': dependencies: '@jridgewell/trace-mapping': 0.3.31 callsites: 3.1.0 graceful-fs: 4.2.11 - '@jest/test-result@29.7.0': + '@jest/test-result@30.2.0': dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.2.0 + '@jest/types': 30.2.0 '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2 - - '@jest/test-sequencer@29.7.0': - dependencies: - '@jest/test-result': 29.7.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - slash: 3.0.0 + collect-v8-coverage: 1.0.3 - '@jest/transform@29.7.0': + '@jest/test-sequencer@30.2.0': dependencies: - '@babel/core': 7.28.4 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.31 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 + '@jest/test-result': 30.2.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 - pirates: 4.0.7 + jest-haste-map: 30.2.0 slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - '@jest/transform@30.1.2': + '@jest/transform@30.2.0': dependencies: - '@babel/core': 7.28.4 - '@jest/types': 30.0.5 + '@babel/core': 7.28.5 + '@jest/types': 30.2.0 '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 7.0.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-haste-map: 30.1.0 + jest-haste-map: 30.2.0 jest-regex-util: 30.0.1 - jest-util: 30.0.5 + jest-util: 30.2.0 micromatch: 4.0.8 pirates: 4.0.7 slash: 3.0.0 @@ -11395,17 +11710,17 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/yargs': 17.0.33 chalk: 4.1.2 - '@jest/types@30.0.5': + '@jest/types@30.2.0': dependencies: '@jest/pattern': 30.0.1 '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -11442,7 +11757,7 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/buffers@1.0.0(tslib@2.8.1)': + '@jsonjoy.com/buffers@1.2.1(tslib@2.8.1)': dependencies: tslib: 2.8.1 @@ -11450,15 +11765,16 @@ snapshots: dependencies: tslib: 2.8.1 - '@jsonjoy.com/json-pack@1.14.0(tslib@2.8.1)': + '@jsonjoy.com/json-pack@1.21.0(tslib@2.8.1)': dependencies: '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) - '@jsonjoy.com/buffers': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) '@jsonjoy.com/json-pointer': 1.0.2(tslib@2.8.1) '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) hyperdyperid: 1.2.0 thingies: 2.5.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) tslib: 2.8.1 '@jsonjoy.com/json-pointer@1.0.2(tslib@2.8.1)': @@ -11469,7 +11785,7 @@ snapshots: '@jsonjoy.com/util@1.9.0(tslib@2.8.1)': dependencies: - '@jsonjoy.com/buffers': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) tslib: 2.8.1 @@ -11477,10 +11793,10 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} - '@listr2/prompt-adapter-inquirer@3.0.1(@inquirer/prompts@7.8.2(@types/node@22.18.6))(@types/node@22.18.6)(listr2@9.0.1)': + '@listr2/prompt-adapter-inquirer@3.0.1(@inquirer/prompts@7.8.2(@types/node@24.9.2))(@types/node@24.9.2)(listr2@9.0.1)': dependencies: - '@inquirer/prompts': 7.8.2(@types/node@22.18.6) - '@inquirer/type': 3.0.8(@types/node@22.18.6) + '@inquirer/prompts': 7.8.2(@types/node@24.9.2) + '@inquirer/type': 3.0.9(@types/node@24.9.2) listr2: 9.0.1 transitivePeerDependencies: - '@types/node' @@ -11624,28 +11940,21 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@napi-rs/wasm-runtime@1.0.5': + '@nestjs/cache-manager@3.0.1(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(cache-manager@7.2.4)(keyv@5.5.3)(rxjs@7.8.2)': dependencies: - '@emnapi/core': 1.5.0 - '@emnapi/runtime': 1.5.0 - '@tybys/wasm-util': 0.10.1 - optional: true - - '@nestjs/cache-manager@3.0.1(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(cache-manager@6.4.3)(keyv@5.5.2)(rxjs@7.8.2)': - dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) - cache-manager: 6.4.3 - keyv: 5.5.2 + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) + cache-manager: 7.2.4 + keyv: 5.5.3 rxjs: 7.8.2 - '@nestjs/cli@11.0.10(@types/node@22.18.6)': + '@nestjs/cli@11.0.10(@types/node@24.9.2)': dependencies: '@angular-devkit/core': 19.2.15(chokidar@4.0.3) '@angular-devkit/schematics': 19.2.15(chokidar@4.0.3) - '@angular-devkit/schematics-cli': 19.2.15(@types/node@22.18.6)(chokidar@4.0.3) - '@inquirer/prompts': 7.8.0(@types/node@22.18.6) - '@nestjs/schematics': 11.0.7(chokidar@4.0.3)(typescript@5.8.3) + '@angular-devkit/schematics-cli': 19.2.15(@types/node@24.9.2)(chokidar@4.0.3) + '@inquirer/prompts': 7.8.0(@types/node@24.9.2) + '@nestjs/schematics': 11.0.9(chokidar@4.0.3)(typescript@5.8.3) ansis: 4.1.0 chokidar: 4.0.3 cli-table3: 0.6.5 @@ -11666,11 +11975,11 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: file-type: 21.0.0 iterare: 1.2.1 - load-esm: 1.0.2 + load-esm: 1.0.3 reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 @@ -11680,45 +11989,45 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/config@4.0.2(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + '@nestjs/config@4.0.2(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) dotenv: 16.4.7 dotenv-expand: 12.0.1 lodash: 4.17.21 rxjs: 7.8.2 - '@nestjs/core@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 - path-to-regexp: 8.2.0 + path-to-regexp: 8.3.0 reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) - '@nestjs/websockets': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-socket.io@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7) + '@nestjs/websockets': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(@nestjs/platform-socket.io@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/platform-express@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)': + '@nestjs/platform-express@11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.5 express: 5.1.0 multer: 2.0.2 - path-to-regexp: 8.2.0 + path-to-regexp: 8.3.0 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@nestjs/platform-socket.io@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.6)(rxjs@7.8.2)': + '@nestjs/platform-socket.io@11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.7)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/websockets': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-socket.io@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/websockets': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(@nestjs/platform-socket.io@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) rxjs: 7.8.2 socket.io: 4.8.1 tslib: 2.8.1 @@ -11727,75 +12036,86 @@ snapshots: - supports-color - utf-8-validate - '@nestjs/schedule@5.0.1(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)': + '@nestjs/schedule@5.0.1(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) cron: 3.5.0 - '@nestjs/schematics@11.0.7(chokidar@4.0.3)(typescript@5.8.3)': + '@nestjs/schematics@11.0.9(chokidar@4.0.3)(typescript@5.8.3)': dependencies: - '@angular-devkit/core': 19.2.15(chokidar@4.0.3) - '@angular-devkit/schematics': 19.2.15(chokidar@4.0.3) - comment-json: 4.2.5 + '@angular-devkit/core': 19.2.17(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.17(chokidar@4.0.3) + comment-json: 4.4.1 jsonc-parser: 3.3.1 pluralize: 8.0.0 typescript: 5.8.3 transitivePeerDependencies: - chokidar - '@nestjs/serve-static@5.0.3(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(express@5.1.0)': + '@nestjs/schematics@11.0.9(chokidar@4.0.3)(typescript@5.9.3)': + dependencies: + '@angular-devkit/core': 19.2.17(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.17(chokidar@4.0.3) + comment-json: 4.4.1 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.9.3 + transitivePeerDependencies: + - chokidar + + '@nestjs/serve-static@5.0.4(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(express@5.1.0)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) - path-to-regexp: 8.2.0 + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) + path-to-regexp: 8.3.0 optionalDependencies: express: 5.1.0 - '@nestjs/testing@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6)': + '@nestjs/testing@11.1.8(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(@nestjs/platform-express@11.1.7)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + '@nestjs/platform-express': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7) - '@nestjs/typeorm@11.0.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(redis@5.8.2)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))': + '@nestjs/typeorm@11.0.0(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.27(pg@8.16.3)(redis@5.8.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 rxjs: 7.8.2 - typeorm: 0.3.27(pg@8.16.3)(redis@5.8.2)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + typeorm: 0.3.27(pg@8.16.3)(redis@5.8.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) - '@nestjs/websockets@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-socket.io@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/websockets@11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(@nestjs/platform-socket.io@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(@nestjs/websockets@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) iterare: 1.2.1 object-hash: 3.0.0 reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-socket.io': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.6)(rxjs@7.8.2) + '@nestjs/platform-socket.io': 11.1.7(@nestjs/common@11.1.7(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.7)(rxjs@7.8.2) - '@ngtools/webpack@20.3.2(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9))': + '@ngtools/webpack@20.3.7(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(typescript@5.9.3)(webpack@5.101.2(esbuild@0.25.9))': dependencies: - '@angular/compiler-cli': 20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3) - typescript: 5.8.3 + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3) + typescript: 5.9.3 webpack: 5.101.2(esbuild@0.25.9) - '@ngx-translate/core@16.0.4(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))': + '@ngx-translate/core@16.0.4(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) tslib: 2.8.1 - '@ngx-translate/http-loader@16.0.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))': + '@ngx-translate/http-loader@16.0.1(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) tslib: 2.8.1 '@noble/hashes@1.8.0': {} @@ -11824,7 +12144,7 @@ snapshots: '@npmcli/fs@4.0.0': dependencies: - semver: 7.7.2 + semver: 7.7.3 '@npmcli/git@6.0.3': dependencies: @@ -11834,7 +12154,7 @@ snapshots: npm-pick-manifest: 10.0.0 proc-log: 5.0.0 promise-retry: 2.0.1 - semver: 7.7.2 + semver: 7.7.3 which: 5.0.0 '@npmcli/installed-package-contents@3.0.0': @@ -11851,7 +12171,7 @@ snapshots: hosted-git-info: 8.1.0 json-parse-even-better-errors: 4.0.0 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-license: 3.0.4 '@npmcli/promise-spawn@8.0.3': @@ -11865,7 +12185,7 @@ snapshots: '@npmcli/node-gyp': 4.0.0 '@npmcli/package-json': 6.2.0 '@npmcli/promise-spawn': 8.0.3 - node-gyp: 11.4.2 + node-gyp: 11.5.0 proc-log: 5.0.0 which: 5.0.0 transitivePeerDependencies: @@ -11878,7 +12198,7 @@ snapshots: '@nx/nx-darwin-arm64@21.2.0': optional: true - '@nx/nx-darwin-x64@20.0.3': + '@nx/nx-darwin-x64@21.6.5': optional: true '@nx/nx-linux-x64-gnu@19.8.2': @@ -11889,10 +12209,6 @@ snapshots: '@opentelemetry/api@1.9.0': {} - '@oxc-project/runtime@0.81.0': {} - - '@oxc-project/types@0.81.0': {} - '@paralleldrive/cuid2@2.2.2': dependencies: '@noble/hashes': 1.8.0 @@ -11963,9 +12279,9 @@ snapshots: '@pkgr/core@0.2.9': {} - '@playwright/test@1.55.1': + '@playwright/test@1.57.0': dependencies: - playwright: 1.55.1 + playwright: 1.57.0 '@polka/send-type@0.5.2': {} @@ -11973,152 +12289,172 @@ snapshots: '@polka/url@1.0.0-next.29': {} - '@redis/bloom@5.8.2(@redis/client@5.8.2)': + '@redis/bloom@5.8.3(@redis/client@5.8.3)': dependencies: - '@redis/client': 5.8.2 + '@redis/client': 5.8.3 - '@redis/client@5.8.2': + '@redis/client@5.8.3': dependencies: cluster-key-slot: 1.1.2 - '@redis/json@5.8.2(@redis/client@5.8.2)': + '@redis/json@5.8.3(@redis/client@5.8.3)': dependencies: - '@redis/client': 5.8.2 + '@redis/client': 5.8.3 - '@redis/search@5.8.2(@redis/client@5.8.2)': + '@redis/search@5.8.3(@redis/client@5.8.3)': dependencies: - '@redis/client': 5.8.2 + '@redis/client': 5.8.3 - '@redis/time-series@5.8.2(@redis/client@5.8.2)': + '@redis/time-series@5.8.3(@redis/client@5.8.3)': dependencies: - '@redis/client': 5.8.2 + '@redis/client': 5.8.3 - '@rolldown/binding-android-arm64@1.0.0-beta.32': + '@rollup/rollup-android-arm-eabi@4.52.3': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.32': + '@rollup/rollup-android-arm-eabi@4.52.5': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.32': + '@rollup/rollup-android-arm64@4.52.3': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.32': + '@rollup/rollup-android-arm64@4.52.5': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.32': + '@rollup/rollup-darwin-arm64@4.52.3': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.32': + '@rollup/rollup-darwin-arm64@4.52.5': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.32': + '@rollup/rollup-darwin-x64@4.52.3': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.32': + '@rollup/rollup-darwin-x64@4.52.5': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.32': + '@rollup/rollup-freebsd-arm64@4.52.3': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.32': + '@rollup/rollup-freebsd-arm64@4.52.5': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.32': - dependencies: - '@napi-rs/wasm-runtime': 1.0.5 + '@rollup/rollup-freebsd-x64@4.52.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.52.5': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.32': + '@rollup/rollup-linux-arm64-musl@4.52.3': optional: true - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.32': + '@rollup/rollup-linux-arm64-musl@4.52.5': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.32': + '@rollup/rollup-linux-loong64-gnu@4.52.3': optional: true - '@rolldown/pluginutils@1.0.0-beta.32': {} + '@rollup/rollup-linux-loong64-gnu@4.52.5': + optional: true - '@rollup/rollup-android-arm-eabi@4.52.2': + '@rollup/rollup-linux-ppc64-gnu@4.52.3': optional: true - '@rollup/rollup-android-arm64@4.52.2': + '@rollup/rollup-linux-ppc64-gnu@4.52.5': optional: true - '@rollup/rollup-darwin-arm64@4.52.2': + '@rollup/rollup-linux-riscv64-gnu@4.52.3': optional: true - '@rollup/rollup-darwin-x64@4.52.2': + '@rollup/rollup-linux-riscv64-gnu@4.52.5': optional: true - '@rollup/rollup-freebsd-arm64@4.52.2': + '@rollup/rollup-linux-riscv64-musl@4.52.3': optional: true - '@rollup/rollup-freebsd-x64@4.52.2': + '@rollup/rollup-linux-riscv64-musl@4.52.5': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.2': + '@rollup/rollup-linux-s390x-gnu@4.52.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.2': + '@rollup/rollup-linux-s390x-gnu@4.52.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.2': + '@rollup/rollup-linux-x64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.2': + '@rollup/rollup-linux-x64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.2': + '@rollup/rollup-linux-x64-musl@4.52.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.2': + '@rollup/rollup-linux-x64-musl@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.2': + '@rollup/rollup-openharmony-arm64@4.52.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.2': + '@rollup/rollup-openharmony-arm64@4.52.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.2': + '@rollup/rollup-win32-arm64-msvc@4.52.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.2': + '@rollup/rollup-win32-arm64-msvc@4.52.5': optional: true - '@rollup/rollup-linux-x64-musl@4.52.2': + '@rollup/rollup-win32-ia32-msvc@4.52.3': optional: true - '@rollup/rollup-openharmony-arm64@4.52.2': + '@rollup/rollup-win32-ia32-msvc@4.52.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.2': + '@rollup/rollup-win32-x64-gnu@4.52.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.2': + '@rollup/rollup-win32-x64-gnu@4.52.5': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.2': + '@rollup/rollup-win32-x64-msvc@4.52.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.2': + '@rollup/rollup-win32-x64-msvc@4.52.5': optional: true '@rtsao/scc@1.1.0': {} - '@schematics/angular@19.2.17(chokidar@4.0.3)': + '@schematics/angular@20.3.7(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 19.2.17(chokidar@4.0.3) - '@angular-devkit/schematics': 19.2.17(chokidar@4.0.3) + '@angular-devkit/core': 20.3.7(chokidar@4.0.3) + '@angular-devkit/schematics': 20.3.7(chokidar@4.0.3) jsonc-parser: 3.3.1 transitivePeerDependencies: - chokidar - '@schematics/angular@20.3.2(chokidar@4.0.3)': + '@schematics/angular@20.3.8(chokidar@4.0.3)': dependencies: - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - '@angular-devkit/schematics': 20.3.2(chokidar@4.0.3) + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) + '@angular-devkit/schematics': 20.3.8(chokidar@4.0.3) jsonc-parser: 3.3.1 transitivePeerDependencies: - chokidar @@ -12177,11 +12513,11 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@stylistic/eslint-plugin@5.4.0(eslint@9.36.0(jiti@1.21.7))': + '@stylistic/eslint-plugin@5.5.0(eslint@9.39.0(jiti@1.21.7))': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@1.21.7)) - '@typescript-eslint/types': 8.44.1 - eslint: 9.36.0(jiti@1.21.7) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.7)) + '@typescript-eslint/types': 8.46.1 + eslint: 9.39.0(jiti@1.21.7) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 @@ -12207,11 +12543,11 @@ snapshots: '@tootallnate/once@2.0.0': {} - '@ts-morph/common@0.27.0': + '@ts-morph/common@0.28.1': dependencies: - fast-glob: 3.3.3 - minimatch: 10.0.3 + minimatch: 10.1.1 path-browserify: 1.0.1 + tinyglobby: 0.2.15 '@tsconfig/node10@1.0.11': {} @@ -12235,52 +12571,56 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/bonjour@3.5.13': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/cache-manager@5.0.0': dependencies: - cache-manager: 6.4.3 + cache-manager: 7.2.4 '@types/connect-history-api-fallback@1.5.4': dependencies: - '@types/express-serve-static-core': 5.0.7 - '@types/node': 22.18.6 + '@types/express-serve-static-core': 5.1.0 + '@types/node': 24.9.2 '@types/connect@3.4.38': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 + + '@types/cookie-parser@1.4.10(@types/express@5.0.5)': + dependencies: + '@types/express': 5.0.5 '@types/cookiejar@2.1.5': {} '@types/cors@2.8.19': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/cron@2.4.3': dependencies: @@ -12370,7 +12710,7 @@ snapshots: '@types/d3-interpolate': 3.0.4 '@types/d3-selection': 3.0.11 - '@types/d3@7.1.0': + '@types/d3@7.4.3': dependencies: '@types/d3-array': 3.2.2 '@types/d3-axis': 3.0.6 @@ -12415,44 +12755,46 @@ snapshots: '@types/estree@1.0.8': {} - '@types/express-serve-static-core@4.19.6': + '@types/express-serve-static-core@4.19.7': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 - '@types/send': 0.17.5 + '@types/send': 1.2.1 - '@types/express-serve-static-core@5.0.7': + '@types/express-serve-static-core@5.1.0': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 - '@types/send': 0.17.5 + '@types/send': 1.2.0 - '@types/express@4.17.23': + '@types/express@4.17.25': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 4.19.6 + '@types/express-serve-static-core': 4.19.7 '@types/qs': 6.14.0 - '@types/serve-static': 1.15.8 + '@types/serve-static': 1.15.10 - '@types/express@5.0.3': + '@types/express@5.0.5': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.0.7 - '@types/serve-static': 1.15.8 + '@types/express-serve-static-core': 5.1.0 + '@types/serve-static': 1.15.10 '@types/geojson@7946.0.16': {} - '@types/graceful-fs@4.1.9': - dependencies: - '@types/node': 22.18.6 + '@types/hammerjs@2.0.46': {} '@types/http-errors@2.0.5': {} '@types/http-proxy@1.17.16': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 + + '@types/http-proxy@1.17.17': + dependencies: + '@types/node': 24.9.2 '@types/istanbul-lib-coverage@2.0.6': {} @@ -12464,16 +12806,20 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 - '@types/jasmine@5.1.9': {} - - '@types/jest@29.5.14': + '@types/jest@30.0.0': dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 + expect: 30.2.0 + pretty-format: 30.2.0 '@types/jsdom@20.0.1': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 + '@types/tough-cookie': 4.0.5 + parse5: 7.3.0 + + '@types/jsdom@21.1.7': + dependencies: + '@types/node': 24.9.2 '@types/tough-cookie': 4.0.5 parse5: 7.3.0 @@ -12481,6 +12827,11 @@ snapshots: '@types/json5@0.0.29': {} + '@types/jsonwebtoken@9.0.10': + dependencies: + '@types/ms': 2.1.0 + '@types/node': 24.9.2 + '@types/luxon@3.4.2': {} '@types/luxon@3.7.1': {} @@ -12491,13 +12842,15 @@ snapshots: '@types/mousetrap@1.6.15': {} + '@types/ms@2.1.0': {} + '@types/node-forge@1.3.14': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 - '@types/node@22.18.6': + '@types/node@24.9.2': dependencies: - undici-types: 6.21.0 + undici-types: 7.16.0 '@types/pako@2.0.4': {} @@ -12510,24 +12863,32 @@ snapshots: '@types/retry@0.12.2': {} - '@types/send@0.17.5': + '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.18.6 + '@types/node': 24.9.2 + + '@types/send@1.2.0': + dependencies: + '@types/node': 24.9.2 + + '@types/send@1.2.1': + dependencies: + '@types/node': 24.9.2 '@types/serve-index@1.9.4': dependencies: - '@types/express': 5.0.3 + '@types/express': 5.0.5 - '@types/serve-static@1.15.8': + '@types/serve-static@1.15.10': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 22.18.6 - '@types/send': 0.17.5 + '@types/node': 24.9.2 + '@types/send': 0.17.6 '@types/sockjs@0.3.36': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/stack-utils@2.0.3': {} @@ -12535,7 +12896,7 @@ snapshots: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 22.18.6 + '@types/node': 24.9.2 form-data: 4.0.4 '@types/supertest@6.0.3': @@ -12554,7 +12915,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@types/yargs-parser@21.0.3': {} @@ -12562,97 +12923,149 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.44.1 - '@typescript-eslint/type-utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.44.1 - eslint: 9.36.0(jiti@1.21.7) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/type-utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.2 + eslint: 9.39.0(jiti@1.21.7) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.44.1 - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.44.1 + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.46.2 debug: 4.4.3 - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.44.1(typescript@5.8.3)': + '@typescript-eslint/project-service@8.46.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.44.1(typescript@5.8.3) - '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/tsconfig-utils': 8.46.1(typescript@5.9.3) + '@typescript-eslint/types': 8.46.2 debug: 4.4.3 - typescript: 5.8.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.46.2(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) + '@typescript-eslint/types': 8.46.2 + debug: 4.4.3 + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.44.1': + '@typescript-eslint/scope-manager@8.46.1': dependencies: - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/visitor-keys': 8.44.1 + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/visitor-keys': 8.46.1 - '@typescript-eslint/tsconfig-utils@8.44.1(typescript@5.8.3)': + '@typescript-eslint/scope-manager@8.46.2': dependencies: - typescript: 5.8.3 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + + '@typescript-eslint/tsconfig-utils@8.46.1(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 - '@typescript-eslint/type-utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.8.3) - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.36.0(jiti@1.21.7) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + eslint: 9.39.0(jiti@1.21.7) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.44.1': {} + '@typescript-eslint/types@8.46.1': {} - '@typescript-eslint/typescript-estree@8.44.1(typescript@5.8.3)': + '@typescript-eslint/types@8.46.2': {} + + '@typescript-eslint/typescript-estree@8.46.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.44.1(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.44.1(typescript@5.8.3) - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/visitor-keys': 8.44.1 + '@typescript-eslint/project-service': 8.46.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.1(typescript@5.9.3) + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/visitor-keys': 8.46.1 debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3)': + '@typescript-eslint/typescript-estree@8.46.2(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@1.21.7)) - '@typescript-eslint/scope-manager': 8.44.1 - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + '@typescript-eslint/project-service': 8.46.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.3) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.1(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.7)) + '@typescript-eslint/scope-manager': 8.46.1 + '@typescript-eslint/types': 8.46.1 + '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.7)) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.44.1': + '@typescript-eslint/visitor-keys@8.46.1': dependencies: - '@typescript-eslint/types': 8.44.1 + '@typescript-eslint/types': 8.46.1 + eslint-visitor-keys: 4.2.1 + + '@typescript-eslint/visitor-keys@8.46.2': + dependencies: + '@typescript-eslint/types': 8.46.2 eslint-visitor-keys: 4.2.1 '@ungap/structured-clone@1.3.0': {} @@ -12716,9 +13129,11 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-basic-ssl@2.1.0(vite@7.1.5(@types/node@22.18.6)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1))': + '@vercel/oidc@3.0.3': {} + + '@vitejs/plugin-basic-ssl@2.1.0(vite@7.1.11(@types/node@24.9.2)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1))': dependencies: - vite: 7.1.5(@types/node@22.18.6)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1) + vite: 7.1.11(@types/node@24.9.2)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1) '@webassemblyjs/ast@1.14.1': dependencies: @@ -12852,11 +13267,11 @@ snapshots: agent-base@7.1.4: {} - ai@5.0.40(zod@3.25.76): + ai@5.0.80(zod@3.25.76): dependencies: - '@ai-sdk/gateway': 1.0.21(zod@3.25.76) + '@ai-sdk/gateway': 2.0.1(zod@3.25.76) '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.8(zod@3.25.76) + '@ai-sdk/provider-utils': 3.0.12(zod@3.25.76) '@opentelemetry/api': 1.9.0 zod: 3.25.76 @@ -12911,20 +13326,20 @@ snapshots: amdefine@1.0.1: optional: true - angular-eslint@20.3.0(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript-eslint@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(typescript@5.8.3): - dependencies: - '@angular-devkit/core': 20.3.2(chokidar@4.0.3) - '@angular-devkit/schematics': 20.3.2(chokidar@4.0.3) - '@angular-eslint/builder': 20.3.0(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/eslint-plugin': 20.3.0(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/eslint-plugin-template': 20.3.0(@angular-eslint/template-parser@20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/schematics': 20.3.0(@angular-eslint/template-parser@20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(@typescript-eslint/types@8.44.1)(@typescript-eslint/utils@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(chokidar@4.0.3)(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@angular-eslint/template-parser': 20.3.0(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/types': 8.44.1 - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 - typescript-eslint: 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + angular-eslint@20.5.0(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript-eslint@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(typescript@5.9.3): + dependencies: + '@angular-devkit/core': 20.3.8(chokidar@4.0.3) + '@angular-devkit/schematics': 20.3.8(chokidar@4.0.3) + '@angular-eslint/builder': 20.5.0(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@angular-eslint/eslint-plugin': 20.5.0(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@angular-eslint/eslint-plugin-template': 20.5.0(@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/types@8.46.2)(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@angular-eslint/schematics': 20.5.0(@angular-eslint/template-parser@20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(@typescript-eslint/types@8.46.2)(@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(chokidar@4.0.3)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@angular-eslint/template-parser': 20.5.0(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 + typescript-eslint: 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) transitivePeerDependencies: - chokidar - supports-color @@ -13052,8 +13467,8 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: - browserslist: 4.26.2 - caniuse-lite: 1.0.30001743 + browserslist: 4.27.0 + caniuse-lite: 1.0.30001751 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -13066,13 +13481,13 @@ snapshots: axobject-query@4.1.0: {} - babel-jest@29.7.0(@babel/core@7.28.4): + babel-jest@30.2.0(@babel/core@7.28.5): dependencies: - '@babel/core': 7.28.4 - '@jest/transform': 29.7.0 + '@babel/core': 7.28.5 + '@jest/transform': 30.2.0 '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.28.4) + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.2.0(@babel/core@7.28.5) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -13085,16 +13500,6 @@ snapshots: find-up: 5.0.0 webpack: 5.101.2(esbuild@0.25.9) - babel-plugin-istanbul@6.1.1: - dependencies: - '@babel/helper-plugin-utils': 7.27.1 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - babel-plugin-istanbul@7.0.1: dependencies: '@babel/helper-plugin-utils': 7.27.1 @@ -13105,16 +13510,13 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-jest-hoist@29.6.3: + babel-plugin-jest-hoist@30.2.0: dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.28.0 babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.3): dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.3 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) semver: 6.3.1 @@ -13123,7 +13525,7 @@ snapshots: babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.4): dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.4 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) semver: 6.3.1 @@ -13134,7 +13536,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - core-js-compat: 3.45.1 + core-js-compat: 3.46.0 transitivePeerDependencies: - supports-color @@ -13142,7 +13544,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.45.1 + core-js-compat: 3.46.0 transitivePeerDependencies: - supports-color @@ -13160,30 +13562,30 @@ snapshots: transitivePeerDependencies: - supports-color - babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.4): - dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.4) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.4) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.4) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.4) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.4) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.4) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.4) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.4) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.4) - - babel-preset-jest@29.6.3(@babel/core@7.28.4): - dependencies: - '@babel/core': 7.28.4 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) + babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.5): + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.5) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.5) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.5) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.5) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.5) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.5) + + babel-preset-jest@30.2.0(@babel/core@7.28.5): + dependencies: + '@babel/core': 7.28.5 + babel-plugin-jest-hoist: 30.2.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) balanced-match@1.0.2: {} @@ -13194,7 +13596,9 @@ snapshots: base64id@2.0.0: {} - baseline-browser-mapping@2.8.6: {} + baseline-browser-mapping@2.8.17: {} + + baseline-browser-mapping@2.8.20: {} basic-auth@2.0.1: dependencies: @@ -13282,13 +13686,21 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.26.2: + browserslist@4.26.3: dependencies: - baseline-browser-mapping: 2.8.6 - caniuse-lite: 1.0.30001743 - electron-to-chromium: 1.5.223 - node-releases: 2.0.21 - update-browserslist-db: 1.1.3(browserslist@4.26.2) + baseline-browser-mapping: 2.8.17 + caniuse-lite: 1.0.30001751 + electron-to-chromium: 1.5.237 + node-releases: 2.0.25 + update-browserslist-db: 1.1.3(browserslist@4.26.3) + + browserslist@4.27.0: + dependencies: + baseline-browser-mapping: 2.8.20 + caniuse-lite: 1.0.30001751 + electron-to-chromium: 1.5.240 + node-releases: 2.0.26 + update-browserslist-db: 1.1.4(browserslist@4.27.0) bs-logger@0.2.6: dependencies: @@ -13298,6 +13710,8 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} buffer@5.7.1: @@ -13335,9 +13749,10 @@ snapshots: tar: 7.5.1 unique-filename: 4.0.0 - cache-manager@6.4.3: + cache-manager@7.2.4: dependencies: - keyv: 5.5.2 + '@cacheable/utils': 2.1.0 + keyv: 5.5.3 call-bind-apply-helpers@1.0.2: dependencies: @@ -13364,13 +13779,13 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001743: {} + caniuse-lite@1.0.30001751: {} canvg@3.0.11: dependencies: '@babel/runtime': 7.28.4 '@types/raf': 3.4.3 - core-js: 3.45.1 + core-js: 3.46.0 raf: 3.4.1 regenerator-runtime: 0.13.11 rgbcolor: 1.0.1 @@ -13436,9 +13851,9 @@ snapshots: ci-info@3.9.0: {} - ci-info@4.3.0: {} + ci-info@4.3.1: {} - cjs-module-lexer@1.4.3: {} + cjs-module-lexer@2.1.0: {} cjson@0.3.0: dependencies: @@ -13447,7 +13862,7 @@ snapshots: class-validator@0.14.2: dependencies: '@types/validator': 13.15.3 - libphonenumber-js: 1.12.22 + libphonenumber-js: 1.12.24 validator: 13.15.15 cli-cursor@3.1.0: @@ -13499,7 +13914,7 @@ snapshots: code-block-writer@13.0.3: {} - collect-v8-coverage@1.0.2: {} + collect-v8-coverage@1.0.3: {} color-convert@2.0.1: dependencies: @@ -13519,7 +13934,7 @@ snapshots: dependencies: delayed-stream: 1.0.0 - commander@14.0.1: {} + commander@14.0.2: {} commander@2.20.3: {} @@ -13527,13 +13942,11 @@ snapshots: commander@7.2.0: {} - comment-json@4.2.5: + comment-json@4.4.1: dependencies: array-timsort: 1.0.3 core-util-is: 1.0.3 esprima: 4.0.1 - has-own-prop: 2.0.0 - repeat-string: 1.6.1 component-emitter@1.3.1: {} @@ -13562,10 +13975,9 @@ snapshots: readable-stream: 3.6.2 typedarray: 0.0.6 - concurrently@9.1.2: + concurrently@9.2.1: dependencies: chalk: 4.1.2 - lodash: 4.17.21 rxjs: 7.8.2 shell-quote: 1.8.3 supports-color: 8.1.1 @@ -13599,6 +14011,11 @@ snapshots: convert-source-map@2.0.0: {} + cookie-parser@1.4.7: + dependencies: + cookie: 0.7.2 + cookie-signature: 1.0.6 + cookie-signature@1.0.6: {} cookie-signature@1.2.2: {} @@ -13617,16 +14034,16 @@ snapshots: dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 tinyglobby: 0.2.15 webpack: 5.101.2(esbuild@0.25.9) - core-js-compat@3.45.1: + core-js-compat@3.46.0: dependencies: - browserslist: 4.26.2 + browserslist: 4.27.0 - core-js@3.45.1: + core-js@3.46.0: optional: true core-util-is@1.0.3: {} @@ -13645,29 +14062,14 @@ snapshots: optionalDependencies: typescript: 5.8.3 - cosmiconfig@9.0.0(typescript@5.8.3): + cosmiconfig@9.0.0(typescript@5.9.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.8.3 - - create-jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node + typescript: 5.9.3 create-require@1.1.1: {} @@ -13701,7 +14103,7 @@ snapshots: postcss-modules-scope: 3.2.1(postcss@8.5.6) postcss-modules-values: 4.0.0(postcss@8.5.6) postcss-value-parser: 4.2.0 - semver: 7.7.2 + semver: 7.7.3 optionalDependencies: webpack: 5.101.2(esbuild@0.25.9) @@ -13856,7 +14258,7 @@ snapshots: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) - d3@7.6.1: + d3@7.9.0: dependencies: d3-array: 3.2.4 d3-axis: 3.0.0 @@ -13987,7 +14389,7 @@ snapshots: detect-libc@1.0.3: optional: true - detect-libc@2.1.1: + detect-libc@2.1.2: optional: true detect-newline@3.1.0: {} @@ -13999,8 +14401,6 @@ snapshots: asap: 2.0.6 wrappy: 1.0.2 - diff-sequences@29.6.3: {} - diff@4.0.2: {} dns-packet@5.6.1: @@ -14027,7 +14427,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.2.4: + dompurify@3.3.0: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -14059,19 +14459,19 @@ snapshots: ebnf-parser@0.1.10: {} - ee-first@1.1.1: {} - - ejs@3.1.10: + ecdsa-sig-formatter@1.0.11: dependencies: - jake: 10.9.4 + safe-buffer: 5.2.1 + + ee-first@1.1.1: {} - electron-to-chromium@1.5.223: {} + electron-to-chromium@1.5.237: {} - emitter-component@1.1.2: {} + electron-to-chromium@1.5.240: {} emittery@0.13.1: {} - emoji-regex@10.5.0: {} + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} @@ -14114,7 +14514,7 @@ snapshots: engine.io@6.6.4: dependencies: '@types/cors': 2.8.19 - '@types/node': 22.18.6 + '@types/node': 24.9.2 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.7.2 @@ -14130,7 +14530,7 @@ snapshots: enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.3 + tapable: 2.3.0 entities@4.5.0: {} @@ -14237,38 +14637,68 @@ snapshots: es6-shim@0.35.8: {} - esbuild-wasm@0.25.10: {} + esbuild-wasm@0.25.11: {} esbuild-wasm@0.25.9: {} - esbuild@0.25.10: + esbuild@0.25.11: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 + optional: true + + esbuild@0.25.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.10 - '@esbuild/android-arm': 0.25.10 - '@esbuild/android-arm64': 0.25.10 - '@esbuild/android-x64': 0.25.10 - '@esbuild/darwin-arm64': 0.25.10 - '@esbuild/darwin-x64': 0.25.10 - '@esbuild/freebsd-arm64': 0.25.10 - '@esbuild/freebsd-x64': 0.25.10 - '@esbuild/linux-arm': 0.25.10 - '@esbuild/linux-arm64': 0.25.10 - '@esbuild/linux-ia32': 0.25.10 - '@esbuild/linux-loong64': 0.25.10 - '@esbuild/linux-mips64el': 0.25.10 - '@esbuild/linux-ppc64': 0.25.10 - '@esbuild/linux-riscv64': 0.25.10 - '@esbuild/linux-s390x': 0.25.10 - '@esbuild/linux-x64': 0.25.10 - '@esbuild/netbsd-arm64': 0.25.10 - '@esbuild/netbsd-x64': 0.25.10 - '@esbuild/openbsd-arm64': 0.25.10 - '@esbuild/openbsd-x64': 0.25.10 - '@esbuild/openharmony-arm64': 0.25.10 - '@esbuild/sunos-x64': 0.25.10 - '@esbuild/win32-arm64': 0.25.10 - '@esbuild/win32-ia32': 0.25.10 - '@esbuild/win32-x64': 0.25.10 + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 esbuild@0.25.9: optionalDependencies: @@ -14323,13 +14753,13 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@10.1.8(eslint@9.36.0(jiti@1.21.7)): + eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@1.21.7)): dependencies: - eslint: 9.36.0(jiti@1.21.7) + eslint: 9.39.0(jiti@1.21.7) eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: - get-tsconfig: 4.10.1 + get-tsconfig: 4.12.0 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.11.1 @@ -14342,33 +14772,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import@2.32.0)(eslint@9.36.0(jiti@1.21.7)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.7)): dependencies: debug: 4.4.3 - eslint: 9.36.0(jiti@1.21.7) + eslint: 9.39.0(jiti@1.21.7) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) - get-tsconfig: 4.10.1 + get-tsconfig: 4.12.0 is-bun-module: 2.0.0 stable-hash-x: 0.2.0 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@1.21.7)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.0(jiti@1.21.7)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@1.21.7)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.0(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.36.0(jiti@1.21.7)) + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.7)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@1.21.7)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.0(jiti@1.21.7)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -14377,9 +14807,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.36.0(jiti@1.21.7) + eslint: 9.39.0(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.36.0(jiti@1.21.7)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.0(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -14391,19 +14821,19 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@29.0.1(@typescript-eslint/eslint-plugin@8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3): + eslint-plugin-jest@29.0.1(@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) + '@typescript-eslint/utils': 8.46.1(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) transitivePeerDependencies: - supports-color - typescript @@ -14412,15 +14842,15 @@ snapshots: dependencies: tslib: 1.14.1 - eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.36.0(jiti@1.21.7)))(eslint@9.36.0(jiti@1.21.7))(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.0(jiti@1.21.7)))(eslint@9.39.0(jiti@1.21.7))(prettier@3.6.2): dependencies: - eslint: 9.36.0(jiti@1.21.7) + eslint: 9.39.0(jiti@1.21.7) prettier: 3.6.2 prettier-linter-helpers: 1.0.0 synckit: 0.11.11 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@9.36.0(jiti@1.21.7)) + eslint-config-prettier: 10.1.8(eslint@9.39.0(jiti@1.21.7)) eslint-plugin-typeorm@0.0.19: dependencies: @@ -14440,21 +14870,20 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.36.0(jiti@1.21.7): + eslint@9.39.0(jiti@1.21.7): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0(jiti@1.21.7)) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.21.0 - '@eslint/config-helpers': 0.3.1 - '@eslint/core': 0.15.2 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.7)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.36.0 - '@eslint/plugin-kit': 0.3.5 + '@eslint/js': 9.39.0 + '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 @@ -14558,26 +14987,18 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - exit@0.1.2: {} + exit-x@0.2.2: {} - expect@29.7.0: + expect@30.2.0: dependencies: - '@jest/expect-utils': 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - - expect@30.1.2: - dependencies: - '@jest/expect-utils': 30.1.2 + '@jest/expect-utils': 30.2.0 '@jest/get-type': 30.1.0 - jest-matcher-utils: 30.1.2 - jest-message-util: 30.1.0 - jest-mock: 30.0.5 - jest-util: 30.0.5 + jest-matcher-utils: 30.2.0 + jest-message-util: 30.2.0 + jest-mock: 30.2.0 + jest-util: 30.2.0 - exponential-backoff@3.1.2: {} + exponential-backoff@3.1.3: {} express-rate-limit@7.5.1(express@5.1.0): dependencies: @@ -14712,10 +15133,6 @@ snapshots: transitivePeerDependencies: - supports-color - filelist@1.0.4: - dependencies: - minimatch: 5.1.6 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -14799,8 +15216,8 @@ snapshots: minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.7.2 - tapable: 2.2.3 + semver: 7.7.3 + tapable: 2.3.0 typescript: 5.8.3 webpack: 5.100.2 @@ -14871,6 +15288,8 @@ snapshots: functions-have-names@1.2.3: {} + generator-function@2.0.1: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -14909,7 +15328,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.10.1: + get-tsconfig@4.12.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -14921,7 +15340,7 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-to-regex.js@1.0.1(tslib@2.8.1): + glob-to-regex.js@1.2.0(tslib@2.8.1): dependencies: tslib: 2.8.1 @@ -14940,7 +15359,7 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 - minimatch: 10.0.3 + minimatch: 10.1.1 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.0 @@ -14956,9 +15375,7 @@ snapshots: globals@14.0.0: {} - globals@15.15.0: {} - - globals@16.4.0: {} + globals@16.5.0: {} globalthis@1.0.4: dependencies: @@ -14971,8 +15388,6 @@ snapshots: graphemer@1.4.0: {} - hammerjs@2.0.8: {} - handle-thing@2.0.1: {} handlebars@4.7.8: @@ -14988,8 +15403,6 @@ snapshots: has-flag@4.0.0: {} - has-own-prop@2.0.0: {} - has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 @@ -15012,7 +15425,7 @@ snapshots: dependencies: lru-cache: 10.4.3 - hosted-git-info@9.0.0: + hosted-git-info@9.0.2: dependencies: lru-cache: 11.2.2 @@ -15089,15 +15502,15 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-middleware@2.0.9(@types/express@4.17.23): + http-proxy-middleware@2.0.9(@types/express@4.17.25): dependencies: - '@types/http-proxy': 1.17.16 + '@types/http-proxy': 1.17.17 http-proxy: 1.18.1(debug@4.4.3) is-glob: 4.0.3 is-plain-obj: 3.0.0 micromatch: 4.0.8 optionalDependencies: - '@types/express': 4.17.23 + '@types/express': 4.17.25 transitivePeerDependencies: - debug @@ -15140,11 +15553,11 @@ snapshots: hyperdyperid@1.2.0: {} - i18next@25.5.2(typescript@5.8.3): + i18next@25.5.3(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.4 optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.3 iconv-lite@0.4.24: dependencies: @@ -15166,7 +15579,7 @@ snapshots: ignore-walk@8.0.0: dependencies: - minimatch: 10.0.3 + minimatch: 10.1.1 ignore@5.3.2: {} @@ -15177,7 +15590,7 @@ snapshots: immediate@3.0.6: {} - immutable@5.1.3: {} + immutable@5.1.4: {} import-fresh@3.3.1: dependencies: @@ -15249,7 +15662,7 @@ snapshots: is-bun-module@2.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 is-callable@1.2.7: {} @@ -15288,9 +15701,10 @@ snapshots: is-generator-fn@2.1.0: {} - is-generator-function@1.1.0: + is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 + generator-function: 2.0.1 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 @@ -15401,23 +15815,13 @@ snapshots: istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.28.4 - '@babel/parser': 7.28.4 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.28.3 - '@babel/parser': 7.28.4 + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.2 + semver: 7.7.3 transitivePeerDependencies: - supports-color @@ -15427,11 +15831,11 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1: + istanbul-lib-source-maps@5.0.6: dependencies: + '@jridgewell/trace-mapping': 0.3.31 debug: 4.4.3 istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 transitivePeerDependencies: - supports-color @@ -15452,124 +15856,113 @@ snapshots: dependencies: '@isaacs/cliui': 8.0.2 - jake@10.9.4: - dependencies: - async: 3.2.6 - filelist: 1.0.4 - picocolors: 1.1.1 - jest-canvas-mock@2.5.2: dependencies: cssfontparser: 1.2.1 moo-color: 1.0.3 - jest-changed-files@29.7.0: + jest-changed-files@30.2.0: dependencies: execa: 5.1.1 - jest-util: 29.7.0 + jest-util: 30.2.0 p-limit: 3.1.0 - jest-circus@29.7.0: + jest-circus@30.2.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@jest/environment': 30.2.0 + '@jest/expect': 30.2.0 + '@jest/test-result': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.0 is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-each: 30.2.0 + jest-matcher-utils: 30.2.0 + jest-message-util: 30.2.0 + jest-runtime: 30.2.0 + jest-snapshot: 30.2.0 + jest-util: 30.2.0 p-limit: 3.1.0 - pretty-format: 29.7.0 - pure-rand: 6.1.0 + pretty-format: 30.2.0 + pure-rand: 7.0.1 slash: 3.0.0 stack-utils: 2.0.6 transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)): + jest-cli@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + '@jest/test-result': 30.2.0 + '@jest/types': 30.2.0 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - exit: 0.1.2 + exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - jest-util: 29.7.0 - jest-validate: 29.7.0 + jest-config: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + jest-util: 30.2.0 + jest-validate: 30.2.0 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node - jest-config@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)): + jest-config@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)): dependencies: - '@babel/core': 7.28.4 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.2.0 + '@jest/types': 30.2.0 + babel-jest: 30.2.0(@babel/core@7.28.5) chalk: 4.1.2 - ci-info: 3.9.0 + ci-info: 4.3.1 deepmerge: 4.3.1 - glob: 7.2.3 + glob: 10.4.5 graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 + jest-circus: 30.2.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.2.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.2.0 + jest-runner: 30.2.0 + jest-util: 30.2.0 + jest-validate: 30.2.0 micromatch: 4.0.8 parse-json: 5.2.0 - pretty-format: 29.7.0 + pretty-format: 30.2.0 slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 22.18.6 - ts-node: 10.9.2(@types/node@22.18.6)(typescript@5.8.3) + '@types/node': 24.9.2 + ts-node: 10.9.2(@types/node@24.9.2)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-diff@29.7.0: - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - - jest-diff@30.1.2: + jest-diff@30.2.0: dependencies: '@jest/diff-sequences': 30.0.1 '@jest/get-type': 30.1.0 chalk: 4.1.2 - pretty-format: 30.0.5 + pretty-format: 30.2.0 - jest-docblock@29.7.0: + jest-docblock@30.2.0: dependencies: detect-newline: 3.1.0 - jest-each@29.7.0: + jest-each@30.2.0: dependencies: - '@jest/types': 29.6.3 + '@jest/get-type': 30.1.0 + '@jest/types': 30.2.0 chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 + jest-util: 30.2.0 + pretty-format: 30.2.0 jest-environment-jsdom@29.7.0: dependencies: @@ -15577,7 +15970,7 @@ snapshots: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 22.18.6 + '@types/node': 24.9.2 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -15586,88 +15979,42 @@ snapshots: - supports-color - utf-8-validate - jest-environment-node@29.7.0: + jest-environment-node@30.2.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.6 - jest-mock: 29.7.0 - jest-util: 29.7.0 - - jest-get-type@29.6.3: {} - - jest-haste-map@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 22.18.6 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 + '@jest/environment': 30.2.0 + '@jest/fake-timers': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 + jest-mock: 30.2.0 + jest-util: 30.2.0 + jest-validate: 30.2.0 - jest-haste-map@30.1.0: + jest-haste-map@30.2.0: dependencies: - '@jest/types': 30.0.5 - '@types/node': 22.18.6 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 jest-regex-util: 30.0.1 - jest-util: 30.0.5 - jest-worker: 30.1.0 + jest-util: 30.2.0 + jest-worker: 30.2.0 micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - jest-jasmine2@29.7.0: - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.6 - chalk: 4.1.2 - co: 4.6.0 - is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - p-limit: 3.1.0 - pretty-format: 29.7.0 - transitivePeerDependencies: - - supports-color - - jest-leak-detector@29.7.0: - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - - jest-matcher-utils@29.7.0: + jest-leak-detector@30.2.0: dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 + '@jest/get-type': 30.1.0 + pretty-format: 30.2.0 - jest-matcher-utils@30.1.2: + jest-matcher-utils@30.2.0: dependencies: '@jest/get-type': 30.1.0 chalk: 4.1.2 - jest-diff: 30.1.2 - pretty-format: 30.0.5 + jest-diff: 30.2.0 + pretty-format: 30.2.0 jest-message-util@29.7.0: dependencies: @@ -15681,49 +16028,49 @@ snapshots: slash: 3.0.0 stack-utils: 2.0.6 - jest-message-util@30.1.0: + jest-message-util@30.2.0: dependencies: '@babel/code-frame': 7.27.1 - '@jest/types': 30.0.5 + '@jest/types': 30.2.0 '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 micromatch: 4.0.8 - pretty-format: 30.0.5 + pretty-format: 30.2.0 slash: 3.0.0 stack-utils: 2.0.6 jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@types/node': 24.9.2 jest-util: 29.7.0 - jest-mock@30.0.5: + jest-mock@30.2.0: dependencies: - '@jest/types': 30.0.5 - '@types/node': 22.18.6 - jest-util: 30.0.5 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 + jest-util: 30.2.0 - jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + jest-pnp-resolver@1.2.3(jest-resolve@30.2.0): optionalDependencies: - jest-resolve: 29.7.0 + jest-resolve: 30.2.0 - jest-preset-angular@14.6.0(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(jsdom@20.0.3)(typescript@5.8.3): + jest-preset-angular@14.6.0(@angular/compiler-cli@20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(jsdom@20.0.3)(typescript@5.9.3): dependencies: - '@angular/compiler-cli': 20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser-dynamic': 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))) + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser-dynamic': 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))) bs-logger: 0.2.6 - esbuild-wasm: 0.25.10 - jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + esbuild-wasm: 0.25.11 + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) jest-environment-jsdom: 29.7.0 jest-util: 29.7.0 pretty-format: 29.7.0 - ts-jest: 29.4.0(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3) - typescript: 5.8.3 + ts-jest: 29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.25.11)(jest-util@29.7.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3) + typescript: 5.9.3 optionalDependencies: - esbuild: 0.25.10 + esbuild: 0.25.11 jsdom: 20.0.3 transitivePeerDependencies: - '@babel/core' @@ -15735,155 +16082,126 @@ snapshots: - supports-color - utf-8-validate - jest-preset-angular@14.6.1(@angular/compiler-cli@20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser-dynamic@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))))(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(jsdom@20.0.3)(typescript@5.8.3): + jest-preset-angular@15.0.3(e802ad861324f03ef4b0eb9da0770013): dependencies: - '@angular/compiler-cli': 20.3.1(@angular/compiler@20.3.1)(typescript@5.8.3) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser-dynamic': 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.1)(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))) + '@angular/compiler-cli': 20.3.7(@angular/compiler@20.3.7)(typescript@5.9.3) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/platform-browser-dynamic': 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.7)(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))) + '@jest/environment-jsdom-abstract': 30.2.0(jsdom@20.0.3) bs-logger: 0.2.6 - esbuild-wasm: 0.25.10 - jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - jest-environment-jsdom: 29.7.0 - jest-util: 29.7.0 - pretty-format: 29.7.0 - ts-jest: 29.4.0(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3) - typescript: 5.8.3 - optionalDependencies: - esbuild: 0.25.10 + esbuild-wasm: 0.25.11 + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + jest-util: 30.2.0 jsdom: 20.0.3 + pretty-format: 30.2.0 + ts-jest: 29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.25.11)(jest-util@30.2.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3) + typescript: 5.9.3 + optionalDependencies: + esbuild: 0.25.11 transitivePeerDependencies: - '@babel/core' - '@jest/transform' - '@jest/types' - babel-jest - - bufferutil - canvas - - supports-color - - utf-8-validate - - jest-regex-util@29.6.3: {} jest-regex-util@30.0.1: {} - jest-resolve-dependencies@29.7.0: + jest-resolve-dependencies@30.2.0: dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 + jest-regex-util: 30.0.1 + jest-snapshot: 30.2.0 transitivePeerDependencies: - supports-color - jest-resolve@29.7.0: + jest-resolve@30.2.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.10 - resolve.exports: 2.0.3 + jest-haste-map: 30.2.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.2.0) + jest-util: 30.2.0 + jest-validate: 30.2.0 slash: 3.0.0 + unrs-resolver: 1.11.1 - jest-runner@29.7.0: + jest-runner@30.2.0: dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@jest/console': 30.2.0 + '@jest/environment': 30.2.0 + '@jest/test-result': 30.2.0 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 chalk: 4.1.2 emittery: 0.13.1 + exit-x: 0.2.2 graceful-fs: 4.2.11 - jest-docblock: 29.7.0 - jest-environment-node: 29.7.0 - jest-haste-map: 29.7.0 - jest-leak-detector: 29.7.0 - jest-message-util: 29.7.0 - jest-resolve: 29.7.0 - jest-runtime: 29.7.0 - jest-util: 29.7.0 - jest-watcher: 29.7.0 - jest-worker: 29.7.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.2.0 + jest-haste-map: 30.2.0 + jest-leak-detector: 30.2.0 + jest-message-util: 30.2.0 + jest-resolve: 30.2.0 + jest-runtime: 30.2.0 + jest-util: 30.2.0 + jest-watcher: 30.2.0 + jest-worker: 30.2.0 p-limit: 3.1.0 source-map-support: 0.5.13 transitivePeerDependencies: - supports-color - jest-runtime@29.7.0: + jest-runtime@30.2.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@jest/environment': 30.2.0 + '@jest/fake-timers': 30.2.0 + '@jest/globals': 30.2.0 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.2.0 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 chalk: 4.1.2 - cjs-module-lexer: 1.4.3 - collect-v8-coverage: 1.0.2 - glob: 7.2.3 + cjs-module-lexer: 2.1.0 + collect-v8-coverage: 1.0.3 + glob: 10.4.5 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-haste-map: 30.2.0 + jest-message-util: 30.2.0 + jest-mock: 30.2.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.2.0 + jest-snapshot: 30.2.0 + jest-util: 30.2.0 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - jest-snapshot@29.7.0: + jest-snapshot@30.2.0: dependencies: - '@babel/core': 7.28.4 - '@babel/generator': 7.28.3 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) - '@babel/types': 7.28.4 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.11 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - natural-compare: 1.4.0 - pretty-format: 29.7.0 - semver: 7.7.2 - transitivePeerDependencies: - - supports-color - - jest-snapshot@30.1.2: - dependencies: - '@babel/core': 7.28.4 - '@babel/generator': 7.28.3 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@babel/generator': 7.28.5 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) '@babel/types': 7.28.4 - '@jest/expect-utils': 30.1.2 + '@jest/expect-utils': 30.2.0 '@jest/get-type': 30.1.0 - '@jest/snapshot-utils': 30.1.2 - '@jest/transform': 30.1.2 - '@jest/types': 30.0.5 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) + '@jest/snapshot-utils': 30.2.0 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) chalk: 4.1.2 - expect: 30.1.2 + expect: 30.2.0 graceful-fs: 4.2.11 - jest-diff: 30.1.2 - jest-matcher-utils: 30.1.2 - jest-message-util: 30.1.0 - jest-util: 30.0.5 - pretty-format: 30.0.5 - semver: 7.7.2 + jest-diff: 30.2.0 + jest-matcher-utils: 30.2.0 + jest-message-util: 30.2.0 + jest-util: 30.2.0 + pretty-format: 30.2.0 + semver: 7.7.3 synckit: 0.11.11 transitivePeerDependencies: - supports-color @@ -15891,71 +16209,65 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@types/node': 24.9.2 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 - jest-util@30.0.5: + jest-util@30.2.0: dependencies: - '@jest/types': 30.0.5 - '@types/node': 22.18.6 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 chalk: 4.1.2 - ci-info: 4.3.0 + ci-info: 4.3.1 graceful-fs: 4.2.11 picomatch: 4.0.3 - jest-validate@29.7.0: + jest-validate@30.2.0: dependencies: - '@jest/types': 29.6.3 + '@jest/get-type': 30.1.0 + '@jest/types': 30.2.0 camelcase: 6.3.0 chalk: 4.1.2 - jest-get-type: 29.6.3 leven: 3.1.0 - pretty-format: 29.7.0 + pretty-format: 30.2.0 - jest-watcher@29.7.0: + jest-watcher@30.2.0: dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.18.6 + '@jest/test-result': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 24.9.2 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 - jest-util: 29.7.0 + jest-util: 30.2.0 string-length: 4.0.2 jest-worker@27.5.1: dependencies: - '@types/node': 22.18.6 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jest-worker@29.7.0: - dependencies: - '@types/node': 22.18.6 - jest-util: 29.7.0 + '@types/node': 24.9.2 merge-stream: 2.0.0 supports-color: 8.1.1 - jest-worker@30.1.0: + jest-worker@30.2.0: dependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 '@ungap/structured-clone': 1.3.0 - jest-util: 30.0.5 + jest-util: 30.2.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)): + jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) - '@jest/types': 29.6.3 + '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + '@jest/types': 30.2.0 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + jest-cli: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node @@ -16058,6 +16370,19 @@ snapshots: jsonparse@1.3.1: {} + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.7.3 + jspdf@3.0.3: dependencies: '@babel/runtime': 7.28.4 @@ -16065,10 +16390,21 @@ snapshots: fflate: 0.8.2 optionalDependencies: canvg: 3.0.11 - core-js: 3.45.1 - dompurify: 3.2.4 + core-js: 3.46.0 + dompurify: 3.3.0 html2canvas: 1.4.1 + jwa@1.4.2: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@3.2.2: + dependencies: + jwa: 1.4.2 + safe-buffer: 5.2.1 + karma-source-map-support@1.4.0: dependencies: source-map-support: 0.5.21 @@ -16079,14 +16415,12 @@ snapshots: dependencies: json-buffer: 3.0.1 - keyv@5.5.2: + keyv@5.5.3: dependencies: '@keyv/serialize': 1.1.1 kind-of@6.0.3: {} - kleur@3.0.3: {} - launch-editor@2.11.1: dependencies: picocolors: 1.1.1 @@ -16121,7 +16455,7 @@ snapshots: lex-parser@0.1.4: {} - libphonenumber-js@1.12.22: {} + libphonenumber-js@1.12.24: {} license-webpack-plugin@4.0.2(webpack@5.101.2(esbuild@0.25.9)): dependencies: @@ -16161,9 +16495,9 @@ snapshots: '@lmdb/lmdb-win32-x64': 3.4.2 optional: true - load-esm@1.0.2: {} + load-esm@1.0.3: {} - loader-runner@4.3.0: {} + loader-runner@4.3.1: {} loader-utils@2.0.4: dependencies: @@ -16187,10 +16521,24 @@ snapshots: lodash.debounce@4.0.8: {} + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -16243,7 +16591,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 make-error@1.3.6: {} @@ -16285,11 +16633,11 @@ snapshots: dependencies: fs-monkey: 1.1.0 - memfs@4.46.0: + memfs@4.49.0: dependencies: - '@jsonjoy.com/json-pack': 1.14.0(tslib@2.8.1) + '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) - glob-to-regex.js: 1.0.1(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) thingies: 2.5.0(tslib@2.8.1) tree-dump: 1.1.0(tslib@2.8.1) tslib: 2.8.1 @@ -16331,13 +16679,13 @@ snapshots: mini-css-extract-plugin@2.9.4(webpack@5.101.2(esbuild@0.25.9)): dependencies: - schema-utils: 4.3.2 - tapable: 2.2.3 + schema-utils: 4.3.3 + tapable: 2.3.0 webpack: 5.101.2(esbuild@0.25.9) minimalistic-assert@1.0.1: {} - minimatch@10.0.3: + minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -16345,10 +16693,6 @@ snapshots: dependencies: brace-expansion: 1.1.12 - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 @@ -16402,8 +16746,6 @@ snapshots: mkdirp@1.0.4: {} - moment@2.30.1: {} - moo-color@1.0.3: dependencies: color-name: 1.1.4 @@ -16462,7 +16804,7 @@ snapshots: nanoid@3.3.11: {} - napi-postinstall@0.3.3: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -16482,18 +16824,18 @@ snapshots: neotraverse@0.6.18: {} - ngx-color-picker@17.0.0(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)): + ngx-color-picker@17.0.0(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/forms@20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)): dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/forms': 20.3.1(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/forms': 20.3.7(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) tslib: 2.8.1 - ngx-toastr@19.1.0(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))): + ngx-toastr@19.1.0(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))): dependencies: - '@angular/common': 20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) - '@angular/core': 20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1) - '@angular/platform-browser': 20.3.1(@angular/animations@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.1(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.1(@angular/compiler@20.3.1)(rxjs@7.8.2)(zone.js@0.15.1)) + '@angular/common': 20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2) + '@angular/core': 20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1) + '@angular/platform-browser': 20.3.7(@angular/animations@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.7(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.7(@angular/compiler@20.3.7)(rxjs@7.8.2)(zone.js@0.15.1)) tslib: 2.8.1 node-abort-controller@3.1.1: {} @@ -16512,18 +16854,18 @@ snapshots: node-gyp-build-optional-packages@5.2.2: dependencies: - detect-libc: 2.1.1 + detect-libc: 2.1.2 optional: true - node-gyp@11.4.2: + node-gyp@11.5.0: dependencies: env-paths: 2.2.1 - exponential-backoff: 3.1.2 + exponential-backoff: 3.1.3 graceful-fs: 4.2.11 make-fetch-happen: 14.0.3 nopt: 8.1.0 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.3 tar: 7.5.1 tinyglobby: 0.2.15 which: 5.0.0 @@ -16532,7 +16874,9 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.21: {} + node-releases@2.0.25: {} + + node-releases@2.0.26: {} nomnom@1.5.2: dependencies: @@ -16553,7 +16897,7 @@ snapshots: npm-install-checks@7.1.2: dependencies: - semver: 7.7.2 + semver: 7.7.3 npm-normalize-package-bin@4.0.0: {} @@ -16561,27 +16905,27 @@ snapshots: dependencies: hosted-git-info: 8.1.0 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-name: 6.0.2 npm-package-arg@13.0.0: dependencies: - hosted-git-info: 9.0.0 + hosted-git-info: 9.0.2 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.3 validate-npm-package-name: 6.0.2 - npm-packlist@10.0.2: + npm-packlist@10.0.3: dependencies: ignore-walk: 8.0.0 - proc-log: 5.0.0 + proc-log: 6.0.0 npm-pick-manifest@10.0.0: dependencies: npm-install-checks: 7.1.2 npm-normalize-package-bin: 4.0.0 npm-package-arg: 12.0.2 - semver: 7.7.2 + semver: 7.7.3 npm-registry-fetch@18.0.2: dependencies: @@ -16768,7 +17112,7 @@ snapshots: fs-minipass: 3.0.3 minipass: 7.1.2 npm-package-arg: 12.0.2 - npm-packlist: 10.0.2 + npm-packlist: 10.0.3 npm-pick-manifest: 10.0.0 npm-registry-fetch: 18.0.2 proc-log: 5.0.0 @@ -16845,7 +17189,7 @@ snapshots: path-to-regexp@0.1.12: {} - path-to-regexp@8.2.0: {} + path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -16914,11 +17258,11 @@ snapshots: dependencies: find-up: 4.1.0 - playwright-core@1.55.1: {} + playwright-core@1.57.0: {} - playwright@1.55.1: + playwright@1.57.0: dependencies: - playwright-core: 1.55.1 + playwright-core: 1.57.0 optionalDependencies: fsevents: 2.3.2 @@ -16931,12 +17275,12 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.8.3)(webpack@5.101.2(esbuild@0.25.9)): + postcss-loader@8.1.1(postcss@8.5.6)(typescript@5.9.3)(webpack@5.101.2(esbuild@0.25.9)): dependencies: - cosmiconfig: 9.0.0(typescript@5.8.3) + cosmiconfig: 9.0.0(typescript@5.9.3) jiti: 1.21.7 postcss: 8.5.6 - semver: 7.7.2 + semver: 7.7.3 optionalDependencies: webpack: 5.101.2(esbuild@0.25.9) transitivePeerDependencies: @@ -16991,7 +17335,7 @@ snapshots: pq@0.0.3: dependencies: async: 3.2.6 - redis: 5.8.2 + redis: 5.8.3 prelude-ls@1.2.1: {} @@ -17007,7 +17351,7 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - pretty-format@30.0.5: + pretty-format@30.2.0: dependencies: '@jest/schemas': 30.0.5 ansi-styles: 5.2.0 @@ -17017,6 +17361,8 @@ snapshots: proc-log@5.0.0: {} + proc-log@6.0.0: {} + process-nextick-args@2.0.1: {} promise-retry@2.0.1: @@ -17024,15 +17370,6 @@ snapshots: err-code: 2.0.3 retry: 0.12.0 - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - propagating-hammerjs@1.5.0: - dependencies: - hammerjs: 2.0.8 - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -17054,9 +17391,9 @@ snapshots: punycode@2.3.1: {} - pure-rand@6.1.0: {} + pure-rand@7.0.1: {} - qr-code-styling@1.9.1: + qr-code-styling@1.9.2: dependencies: qrcode-generator: 1.5.2 @@ -17123,13 +17460,13 @@ snapshots: readdirp@4.1.2: {} - redis@5.8.2: + redis@5.8.3: dependencies: - '@redis/bloom': 5.8.2(@redis/client@5.8.2) - '@redis/client': 5.8.2 - '@redis/json': 5.8.2(@redis/client@5.8.2) - '@redis/search': 5.8.2(@redis/client@5.8.2) - '@redis/time-series': 5.8.2(@redis/client@5.8.2) + '@redis/bloom': 5.8.3(@redis/client@5.8.3) + '@redis/client': 5.8.3 + '@redis/json': 5.8.3(@redis/client@5.8.3) + '@redis/search': 5.8.3(@redis/client@5.8.3) + '@redis/time-series': 5.8.3(@redis/client@5.8.3) reflect-metadata@0.2.2: {} @@ -17179,8 +17516,6 @@ snapshots: dependencies: jsesc: 3.1.0 - repeat-string@1.6.1: {} - require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -17207,14 +17542,18 @@ snapshots: postcss: 8.5.6 source-map: 0.6.1 - resolve.exports@2.0.3: {} - resolve@1.22.10: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -17243,54 +17582,60 @@ snapshots: robust-predicates@3.0.2: {} - rolldown@1.0.0-beta.32: + rollup@4.52.3: dependencies: - '@oxc-project/runtime': 0.81.0 - '@oxc-project/types': 0.81.0 - '@rolldown/pluginutils': 1.0.0-beta.32 - ansis: 4.1.0 + '@types/estree': 1.0.8 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.32 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.32 - '@rolldown/binding-darwin-x64': 1.0.0-beta.32 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.32 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.32 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.32 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.32 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.32 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.32 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.32 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.32 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.32 - '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.32 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.32 - - rollup@4.52.2: + '@rollup/rollup-android-arm-eabi': 4.52.3 + '@rollup/rollup-android-arm64': 4.52.3 + '@rollup/rollup-darwin-arm64': 4.52.3 + '@rollup/rollup-darwin-x64': 4.52.3 + '@rollup/rollup-freebsd-arm64': 4.52.3 + '@rollup/rollup-freebsd-x64': 4.52.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.3 + '@rollup/rollup-linux-arm-musleabihf': 4.52.3 + '@rollup/rollup-linux-arm64-gnu': 4.52.3 + '@rollup/rollup-linux-arm64-musl': 4.52.3 + '@rollup/rollup-linux-loong64-gnu': 4.52.3 + '@rollup/rollup-linux-ppc64-gnu': 4.52.3 + '@rollup/rollup-linux-riscv64-gnu': 4.52.3 + '@rollup/rollup-linux-riscv64-musl': 4.52.3 + '@rollup/rollup-linux-s390x-gnu': 4.52.3 + '@rollup/rollup-linux-x64-gnu': 4.52.3 + '@rollup/rollup-linux-x64-musl': 4.52.3 + '@rollup/rollup-openharmony-arm64': 4.52.3 + '@rollup/rollup-win32-arm64-msvc': 4.52.3 + '@rollup/rollup-win32-ia32-msvc': 4.52.3 + '@rollup/rollup-win32-x64-gnu': 4.52.3 + '@rollup/rollup-win32-x64-msvc': 4.52.3 + fsevents: 2.3.3 + + rollup@4.52.5: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.2 - '@rollup/rollup-android-arm64': 4.52.2 - '@rollup/rollup-darwin-arm64': 4.52.2 - '@rollup/rollup-darwin-x64': 4.52.2 - '@rollup/rollup-freebsd-arm64': 4.52.2 - '@rollup/rollup-freebsd-x64': 4.52.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.2 - '@rollup/rollup-linux-arm-musleabihf': 4.52.2 - '@rollup/rollup-linux-arm64-gnu': 4.52.2 - '@rollup/rollup-linux-arm64-musl': 4.52.2 - '@rollup/rollup-linux-loong64-gnu': 4.52.2 - '@rollup/rollup-linux-ppc64-gnu': 4.52.2 - '@rollup/rollup-linux-riscv64-gnu': 4.52.2 - '@rollup/rollup-linux-riscv64-musl': 4.52.2 - '@rollup/rollup-linux-s390x-gnu': 4.52.2 - '@rollup/rollup-linux-x64-gnu': 4.52.2 - '@rollup/rollup-linux-x64-musl': 4.52.2 - '@rollup/rollup-openharmony-arm64': 4.52.2 - '@rollup/rollup-win32-arm64-msvc': 4.52.2 - '@rollup/rollup-win32-ia32-msvc': 4.52.2 - '@rollup/rollup-win32-x64-gnu': 4.52.2 - '@rollup/rollup-win32-x64-msvc': 4.52.2 + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 fsevents: 2.3.3 router@2.2.0: @@ -17299,7 +17644,7 @@ snapshots: depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.2.0 + path-to-regexp: 8.3.0 transitivePeerDependencies: - supports-color @@ -17354,7 +17699,7 @@ snapshots: sass@1.90.0: dependencies: chokidar: 4.0.3 - immutable: 5.1.3 + immutable: 5.1.4 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 @@ -17372,7 +17717,7 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) - schema-utils@4.3.2: + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 ajv: 8.17.1 @@ -17393,6 +17738,8 @@ snapshots: semver@7.7.2: {} + semver@7.7.3: {} + send@0.19.0: dependencies: debug: 2.6.9 @@ -17491,7 +17838,7 @@ snapshots: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 - to-buffer: 1.2.1 + to-buffer: 1.2.2 shallow-clone@3.0.1: dependencies: @@ -17554,8 +17901,6 @@ snapshots: mrmime: 2.0.1 totalist: 3.0.1 - sisteransi@1.0.5: {} - slash@3.0.0: {} slice-ansi@5.0.0: @@ -17756,7 +18101,7 @@ snapshots: string-width@7.2.0: dependencies: - emoji-regex: 10.5.0 + emoji-regex: 10.6.0 get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 @@ -17857,7 +18202,7 @@ snapshots: tablesort@5.6.0: {} - tapable@2.2.3: {} + tapable@2.3.0: {} tar@6.2.1: dependencies: @@ -17880,7 +18225,7 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.0 webpack: 5.101.2(esbuild@0.25.9) @@ -17891,7 +18236,7 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.0 webpack: 5.100.2 @@ -17941,7 +18286,7 @@ snapshots: tmpl@1.0.5: {} - to-buffer@1.2.1: + to-buffer@1.2.2: dependencies: isarray: 2.0.5 safe-buffer: 5.2.1 @@ -17982,81 +18327,82 @@ snapshots: dependencies: matchit: 1.1.0 - ts-api-utils@2.1.0(typescript@5.8.3): + ts-api-utils@2.1.0(typescript@5.9.3): dependencies: - typescript: 5.8.3 + typescript: 5.9.3 - ts-jest@29.4.0(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(esbuild@0.25.10)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3): + ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.25.11)(jest-util@29.7.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 - ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + handlebars: 4.7.8 + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.2 + semver: 7.7.3 type-fest: 4.41.0 - typescript: 5.8.3 + typescript: 5.9.3 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.28.4 - '@jest/transform': 30.1.2 - '@jest/types': 30.0.5 - babel-jest: 29.7.0(@babel/core@7.28.4) - esbuild: 0.25.10 + '@babel/core': 7.28.5 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + babel-jest: 30.2.0(@babel/core@7.28.5) + esbuild: 0.25.11 jest-util: 29.7.0 - ts-jest@29.4.0(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@30.0.5)(jest@29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)))(typescript@5.8.3): + ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(esbuild@0.25.11)(jest-util@30.2.0)(jest@30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 - ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.18.6)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)) + handlebars: 4.7.8 + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.2 + semver: 7.7.3 type-fest: 4.41.0 - typescript: 5.8.3 + typescript: 5.9.3 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.28.4 - '@jest/transform': 30.1.2 - '@jest/types': 30.0.5 - babel-jest: 29.7.0(@babel/core@7.28.4) - jest-util: 30.0.5 + '@babel/core': 7.28.5 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + babel-jest: 30.2.0(@babel/core@7.28.5) + esbuild: 0.25.11 + jest-util: 30.2.0 - ts-loader@9.5.4(typescript@5.8.3)(webpack@5.101.2): + ts-loader@9.5.4(typescript@5.9.3)(webpack@5.101.2): dependencies: chalk: 4.1.2 enhanced-resolve: 5.18.3 micromatch: 4.0.8 - semver: 7.7.2 + semver: 7.7.3 source-map: 0.7.6 - typescript: 5.8.3 + typescript: 5.9.3 webpack: 5.101.2(esbuild@0.25.9) - ts-morph@26.0.0: + ts-morph@27.0.2: dependencies: - '@ts-morph/common': 0.27.0 + '@ts-morph/common': 0.28.1 code-block-writer: 13.0.3 - ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3): + ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.18.6 + '@types/node': 24.9.2 acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.8.3 + typescript: 5.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -18064,7 +18410,7 @@ snapshots: dependencies: chalk: 4.1.2 enhanced-resolve: 5.18.3 - tapable: 2.2.3 + tapable: 2.3.0 tsconfig-paths: 4.2.0 tsconfig-paths@3.15.0: @@ -18150,7 +18496,7 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.27(pg@8.16.3)(redis@5.8.2)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.6)(typescript@5.8.3)): + typeorm@0.3.27(pg@8.16.3)(redis@5.8.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)): dependencies: '@sqltools/formatter': 1.2.5 ansis: 3.17.0 @@ -18169,25 +18515,27 @@ snapshots: yargs: 17.7.2 optionalDependencies: pg: 8.16.3 - redis: 5.8.2 - ts-node: 10.9.2(@types/node@22.18.6)(typescript@5.8.3) + redis: 5.8.3 + ts-node: 10.9.2(@types/node@24.9.2)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - typescript-eslint@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3): + typescript-eslint@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.44.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - '@typescript-eslint/typescript-estree': 8.44.1(typescript@5.8.3) - '@typescript-eslint/utils': 8.44.1(eslint@9.36.0(jiti@1.21.7))(typescript@5.8.3) - eslint: 9.36.0(jiti@1.21.7) - typescript: 5.8.3 + '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.0(jiti@1.21.7) + typescript: 5.9.3 transitivePeerDependencies: - supports-color typescript@5.8.3: {} + typescript@5.9.3: {} + uglify-js@3.19.3: optional: true @@ -18206,7 +18554,7 @@ snapshots: underscore@1.1.7: {} - undici-types@6.21.0: {} + undici-types@7.16.0: {} undici@7.16.0: {} @@ -18239,7 +18587,7 @@ snapshots: unrs-resolver@1.11.1: dependencies: - napi-postinstall: 0.3.3 + napi-postinstall: 0.3.4 optionalDependencies: '@unrs/resolver-binding-android-arm-eabi': 1.11.1 '@unrs/resolver-binding-android-arm64': 1.11.1 @@ -18261,9 +18609,15 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - update-browserslist-db@1.1.3(browserslist@4.26.2): + update-browserslist-db@1.1.3(browserslist@4.26.3): + dependencies: + browserslist: 4.26.3 + escalade: 3.2.0 + picocolors: 1.1.1 + + update-browserslist-db@1.1.4(browserslist@4.27.0): dependencies: - browserslist: 4.26.2 + browserslist: 4.27.0 escalade: 3.2.0 picocolors: 1.1.1 @@ -18308,45 +18662,56 @@ snapshots: vary@1.1.2: {} - vis@4.21.0-EOL: + vis-data@8.0.3(uuid@11.1.0)(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)): + dependencies: + uuid: 11.1.0 + vis-util: 6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1) + + vis-network@10.0.2(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)(keycharm@0.2.0)(uuid@11.1.0)(vis-data@8.0.3(uuid@11.1.0)(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)))(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)): dependencies: - emitter-component: 1.1.2 - hammerjs: 2.0.8 + '@egjs/hammerjs': 2.0.17 + component-emitter: 1.3.1 keycharm: 0.2.0 - moment: 2.30.1 - propagating-hammerjs: 1.5.0 + uuid: 11.1.0 + vis-data: 8.0.3(uuid@11.1.0)(vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)) + vis-util: 6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1) - vite@6.3.6(@types/node@22.18.6)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.44.0): + vis-util@6.0.0(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1): dependencies: - esbuild: 0.25.10 + '@egjs/hammerjs': 2.0.17 + component-emitter: 1.3.1 + + vite@7.1.11(@types/node@24.9.2)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1): + dependencies: + esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.2 + rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 fsevents: 2.3.3 jiti: 1.21.7 less: 4.4.0 sass: 1.90.0 - terser: 5.44.0 + terser: 5.43.1 - vite@7.1.5(@types/node@22.18.6)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.43.1): + vite@7.1.12(@types/node@24.9.2)(jiti@1.21.7)(less@4.4.0)(sass@1.90.0)(terser@5.44.0): dependencies: - esbuild: 0.25.9 + esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.2 + rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.18.6 + '@types/node': 24.9.2 fsevents: 2.3.3 jiti: 1.21.7 less: 4.4.0 sass: 1.90.0 - terser: 5.43.1 + terser: 5.44.0 w3c-xmlserializer@4.0.0: dependencies: @@ -18377,11 +18742,11 @@ snapshots: webpack-dev-middleware@7.4.2(webpack@5.101.2(esbuild@0.25.9)): dependencies: colorette: 2.0.20 - memfs: 4.46.0 + memfs: 4.49.0 mime-types: 2.1.35 on-finished: 2.4.1 range-parser: 1.2.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 optionalDependencies: webpack: 5.101.2(esbuild@0.25.9) @@ -18389,10 +18754,10 @@ snapshots: dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.23 - '@types/express-serve-static-core': 4.19.6 + '@types/express': 4.17.25 + '@types/express-serve-static-core': 4.19.7 '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.8 + '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 '@types/ws': 8.18.1 ansi-html-community: 0.0.8 @@ -18403,12 +18768,12 @@ snapshots: connect-history-api-fallback: 2.0.0 express: 4.21.2 graceful-fs: 4.2.11 - http-proxy-middleware: 2.0.9(@types/express@4.17.23) + http-proxy-middleware: 2.0.9(@types/express@4.17.25) ipaddr.js: 2.2.0 launch-editor: 2.11.1 open: 10.2.0 p-retry: 6.2.1 - schema-utils: 4.3.2 + schema-utils: 4.3.3 selfsigned: 2.4.1 serve-index: 1.9.1 sockjs: 0.3.24 @@ -18448,7 +18813,7 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.15.0 acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.26.2 + browserslist: 4.26.3 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.3 es-module-lexer: 1.7.0 @@ -18457,11 +18822,11 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.1 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.3 + schema-utils: 4.3.3 + tapable: 2.3.0 terser-webpack-plugin: 5.3.14(webpack@5.100.2) watchpack: 2.4.4 webpack-sources: 3.3.3 @@ -18480,7 +18845,7 @@ snapshots: '@webassemblyjs/wasm-parser': 1.14.1 acorn: 8.15.0 acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.26.2 + browserslist: 4.27.0 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.3 es-module-lexer: 1.7.0 @@ -18489,11 +18854,11 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.1 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 4.3.2 - tapable: 2.2.3 + schema-utils: 4.3.3 + tapable: 2.3.0 terser-webpack-plugin: 5.3.14(esbuild@0.25.9)(webpack@5.101.2(esbuild@0.25.9)) watchpack: 2.4.4 webpack-sources: 3.3.3 @@ -18543,7 +18908,7 @@ snapshots: is-async-function: 2.1.1 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 + is-generator-function: 1.1.2 is-regex: 1.2.1 is-weakref: 1.1.1 isarray: 2.0.5 @@ -18612,11 +18977,6 @@ snapshots: wrappy@1.0.2: {} - write-file-atomic@4.0.2: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 diff --git a/teammapper-backend/.env.default b/teammapper-backend/.env.default index 86c9b7fe2..a09fbdfdd 100644 --- a/teammapper-backend/.env.default +++ b/teammapper-backend/.env.default @@ -12,4 +12,4 @@ POSTGRES_TEST_USER= POSTGRES_TEST_PASSWORD= POSTGRES_TEST_DATABASE= -DELETE_AFTER_DAYS= \ No newline at end of file +DELETE_AFTER_DAYS= diff --git a/teammapper-backend/CLAUDE.md b/teammapper-backend/CLAUDE.md index f7ce088e8..2647f7663 100644 --- a/teammapper-backend/CLAUDE.md +++ b/teammapper-backend/CLAUDE.md @@ -9,9 +9,10 @@ TeamMapper is a collaborative web-based mind mapping application built with Angu ## Development best pracices - **Reusing existing code**: Please check before adding new types and functions if code is already available that solves the same purpose and that can be reused -- **Be specific with types**: Request explicit interfaces, enums, and type annotations rather than `any` +- **Be specific with types**: Request explicit interfaces, enums, and type annotations rather than `any`. ``any`is forbidden. Do only use typescript line ignores when absolutely necessary. - **Include error handling**: Ask for proper try/catch blocks and error types - **Request documentation**: Ask for comments on functions and complex types, but no need for full JSDoc +- **Method length**: Methods should usually have a maximum of 10 lines. If it exceeds this maximum, please use the extract method pattern. All methods should be well described and easy to read. ## Development Workflow diff --git a/teammapper-backend/config/settings.dev.json b/teammapper-backend/config/settings.dev.json new file mode 100644 index 000000000..fe7eab673 --- /dev/null +++ b/teammapper-backend/config/settings.dev.json @@ -0,0 +1,69 @@ +{ + "systemSettings": { + "info": { + "name": "TeamMapper", + "version": "0.2.1" + }, + "urls": { + "pictogramApiUrl": "/arasaac/api/pictograms", + "pictogramStaticUrl": "/arasaac/images/pictograms" + }, + "featureFlags": { + "pictograms": true, + "ai": true + } + }, + "userSettings": { + "general": { + "language": "en" + }, + "mapOptions": { + "centerOnResize": false, + "autoBranchColors": true, + "showLinktext": false, + "fontMaxSize": 70, + "fontMinSize": 15, + "fontIncrement": 5, + "defaultNode": { + "name": "", + "link": { + "href": "" + }, + "image": { + "src": "", + "size": 60 + }, + "colors": { + "name": "#666666", + "background": "#f5f5f5", + "branch": "#546e7a" + }, + "font": { + "size": 22, + "style": "normal", + "weight": "normal" + }, + "locked": true + }, + "rootNode": { + "name": "Root node", + "link": { + "href": "" + }, + "image": { + "src": "", + "size": 70 + }, + "colors": { + "name": "#666666", + "background": "#f5f5f5" + }, + "font": { + "size": 26, + "style": "normal", + "weight": "normal" + } + } + } + } +} \ No newline at end of file diff --git a/teammapper-backend/config/settings.prod.json b/teammapper-backend/config/settings.prod.json new file mode 100644 index 000000000..8333aee89 --- /dev/null +++ b/teammapper-backend/config/settings.prod.json @@ -0,0 +1,69 @@ +{ + "systemSettings": { + "info": { + "name": "TeamMapper", + "version": "0.2.1" + }, + "urls": { + "pictogramApiUrl": "/arasaac/api/pictograms", + "pictogramStaticUrl": "/arasaac/images/pictograms" + }, + "featureFlags": { + "pictograms": true, + "ai": true + } + }, + "userSettings": { + "general": { + "language": "de" + }, + "mapOptions": { + "centerOnResize": false, + "autoBranchColors": true, + "showLinktext": false, + "fontMaxSize": 70, + "fontMinSize": 15, + "fontIncrement": 5, + "defaultNode": { + "name": "", + "link": { + "href": "" + }, + "image": { + "src": "", + "size": 60 + }, + "colors": { + "name": "#666666", + "background": "#f5f5f5", + "branch": "#546e7a" + }, + "font": { + "size": 22, + "style": "normal", + "weight": "normal" + }, + "locked": true + }, + "rootNode": { + "name": "Thema", + "link": { + "href": "" + }, + "image": { + "src": "", + "size": 70 + }, + "colors": { + "name": "#666666", + "background": "#f5f5f5" + }, + "font": { + "size": 26, + "style": "normal", + "weight": "normal" + } + } + } + } +} \ No newline at end of file diff --git a/teammapper-backend/package.json b/teammapper-backend/package.json index e1adf6ca5..a6b5dee24 100644 --- a/teammapper-backend/package.json +++ b/teammapper-backend/package.json @@ -32,52 +32,56 @@ "prod:typeorm:migrate": "typeorm migration:run --dataSource dist/data-source.js" }, "dependencies": { - "@ai-sdk/openai": "2.0.28", - "@ai-sdk/openai-compatible": "1.0.15", - "@nestjs/cache-manager": "^3.0.0", - "@nestjs/cli": "^11.0.7", - "@nestjs/common": "^11.1.5", + "@ai-sdk/openai": "2.0.53", + "@ai-sdk/openai-compatible": "1.0.22", + "@nestjs/cache-manager": "^3.0.1", + "@nestjs/cli": "^11.0.10", + "@nestjs/common": "^11.1.7", "@nestjs/config": "4.0.2", - "@nestjs/core": "^11.1.5", - "@nestjs/platform-express": "^11.1.5", - "@nestjs/platform-socket.io": "^11.1.5", + "@nestjs/core": "^11.1.7", + "@nestjs/platform-express": "^11.1.7", + "@nestjs/platform-socket.io": "^11.1.7", "@nestjs/schedule": "^5.0.1", - "@nestjs/serve-static": "^5.0.3", + "@nestjs/serve-static": "^5.0.4", "@nestjs/typeorm": "^11.0.0", - "@nestjs/websockets": "^11.1.5", + "@nestjs/websockets": "^11.1.7", "@types/uuid": "^10.0.0", - "ai": "5.0.40", - "cache-manager": "^6.4.0", - "class-validator": "^0.14.1", - "dotenv": "16.5.0", + "ai": "5.0.80", + "cache-manager": "^7.2.4", + "class-validator": "^0.14.2", + "deepmerge": "^4.3.1", + "cookie-parser": "^1.4.7", "http-proxy-middleware": "3.0.5", - "pg": "^8.16.0", + "jsonwebtoken": "^9.0.2", + "pg": "^8.16.3", "pq": "^0.0.3", "reflect-metadata": "^0.2.2", "rimraf": "^6.0.1", "rxjs": "^7.8.2", "socket.io": "4.8.1", - "typeorm": "^0.3.26", + "typeorm": "^0.3.27", "uuid": "11.1.0" }, "devDependencies": { - "@eslint/compat": "^1.3.2", - "@eslint/js": "^9.34.0", - "@golevelup/ts-jest": "^0.6.2", - "@jest/globals": "^30.1.2", - "@nestjs/schematics": "^11.0.0", - "@nestjs/testing": "^11.1.5", - "@stylistic/eslint-plugin": "^5.2.3", + "@eslint/compat": "^1.4.1", + "@eslint/js": "^9.39.0", + "@golevelup/ts-jest": "^0.7.0", + "@jest/globals": "^30.2.0", + "@nestjs/schematics": "^11.0.9", + "@nestjs/testing": "^11.1.8", + "@stylistic/eslint-plugin": "^5.5.0", "@types/cache-manager": "5.0.0", + "@types/cookie-parser": "^1.4.10", "@types/cron": "^2.4.3", - "@types/express": "^5.0.0", - "@types/express-serve-static-core": "^5.0.6", - "@types/jest": "29.5.14", - "@types/node": "^22.15.30", + "@types/express": "^5.0.5", + "@types/express-serve-static-core": "^5.1.0", + "@types/jest": "30.0.0", + "@types/jsonwebtoken": "^9.0.10", + "@types/node": "^24.9.2", "@types/supertest": "^6.0.3", - "@typescript-eslint/eslint-plugin": "^8.41.0", - "@typescript-eslint/parser": "^8.41.0", - "eslint": "^9.34.0", + "@typescript-eslint/eslint-plugin": "^8.46.2", + "@typescript-eslint/parser": "^8.46.2", + "eslint": "^9.39.0", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-typescript": "4.4.4", "eslint-plugin-import": "2.32.0", @@ -85,18 +89,17 @@ "eslint-plugin-nestjs": "1.2.3", "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-typeorm": "0.0.19", - "globals": "^16.2.0", - "jest": "29.7.0", - "jest-jasmine2": "29.7.0", + "globals": "^16.5.0", + "jest": "30.2.0", "prettier": "^3.6.2", "socket.io-client": "^4.8.1", - "supertest": "^7.1.1", - "ts-jest": "29.4.0", - "ts-loader": "^9.5.2", + "supertest": "^7.1.4", + "ts-jest": "29.4.5", + "ts-loader": "^9.5.4", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "~5.8.2", - "typescript-eslint": "^8.41.0" + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.2" }, "jest": { "moduleFileExtensions": [ @@ -115,7 +118,6 @@ "modulePaths": [ "" ], - "testRunner": "jest-jasmine2", "coverageDirectory": "../coverage", "testEnvironment": "node" } diff --git a/teammapper-backend/src/app.module.ts b/teammapper-backend/src/app.module.ts index 21d220a69..90da6b9c7 100644 --- a/teammapper-backend/src/app.module.ts +++ b/teammapper-backend/src/app.module.ts @@ -5,12 +5,14 @@ import configService from './config.service' import { MapModule } from './map/map.module' import { ServeStaticModule } from '@nestjs/serve-static' import { join } from 'path' +import { SettingsModule } from './settings/settings.module' @Module({ imports: [ ConfigModule.forRoot(), TypeOrmModule.forRoot(configService.getTypeOrmConfig()), MapModule, + SettingsModule, ServeStaticModule.forRoot({ rootPath: join(__dirname, '..', 'client', 'browser'), exclude: ['/assets/'], diff --git a/teammapper-backend/src/auth/person-id.middleware.ts b/teammapper-backend/src/auth/person-id.middleware.ts new file mode 100644 index 000000000..7f12c115c --- /dev/null +++ b/teammapper-backend/src/auth/person-id.middleware.ts @@ -0,0 +1,26 @@ +import { Injectable, NestMiddleware } from '@nestjs/common' +import jwt from 'jsonwebtoken' +import { Request } from '../map/types' + +@Injectable() +export class PersonIdMiddleware implements NestMiddleware { + use(req: Request, res: Response, next: () => void) { + const secret = process.env.JWT_SECRET + const cookie = req.cookies?.person_id + + req.pid = undefined + + if (secret && cookie) { + try { + const decoded = jwt.verify(cookie, secret, { + algorithms: ['HS256'], + }) as { pid: string } + req.pid = decoded.pid + } catch { + console.warn('Invalid person_id cookie') + } + } + + next() + } +} diff --git a/teammapper-backend/src/config.service.ts b/teammapper-backend/src/config.service.ts index 6b8bb55e4..45290ca73 100644 --- a/teammapper-backend/src/config.service.ts +++ b/teammapper-backend/src/config.service.ts @@ -17,8 +17,6 @@ export interface LLMProps { rpm?: string } -require('dotenv').config() // eslint-disable-line @typescript-eslint/no-require-imports - class ConfigService { private env: EnvProps diff --git a/teammapper-backend/src/map/controllers/maps.controller.spec.ts b/teammapper-backend/src/map/controllers/maps.controller.spec.ts index 54c1cab59..f34b52ae5 100644 --- a/teammapper-backend/src/map/controllers/maps.controller.spec.ts +++ b/teammapper-backend/src/map/controllers/maps.controller.spec.ts @@ -3,7 +3,7 @@ import MapsController from './maps.controller' import { MapsService } from '../services/maps.service' import { NotFoundException } from '@nestjs/common' import { MmpMap } from '../entities/mmpMap.entity' -import { IMmpClientMap, IMmpClientPrivateMap } from '../types' +import { IMmpClientMap, IMmpClientPrivateMap, Request } from '../types' import { MmpNode } from '../entities/mmpNode.entity' import { createClientRootNode, @@ -30,6 +30,7 @@ describe('MapsController', () => { exportMapToClient: jest.fn(), deleteMap: jest.fn(), updateLastAccessed: jest.fn(), + getMapsOfUser: jest.fn(), }, }, ], @@ -116,6 +117,25 @@ describe('MapsController', () => { }) }) + describe('findAll', () => { + it('should return user maps when pid is provided', async () => { + const pid = 'test-person-id' + + await mapsController.findAll({ pid } as Request) + expect(mapsService.getMapsOfUser).toHaveBeenCalledWith(pid) + }) + + it('should return an empty array when pid is missing', async () => { + const response = await mapsController.findAll({} as Request) + expect(response).toEqual([]) + }) + + it('should return an empty array when req is undefined', async () => { + const response = await mapsController.findAll(undefined) + expect(response).toEqual([]) + }) + }) + describe('delete', () => { it('should delete an existing map successfully', async () => { const existingMap = createMmpMap() @@ -171,7 +191,37 @@ describe('MapsController', () => { rootNode, }) - expect(mapsService.createEmptyMap).toHaveBeenCalledWith(rootNode) + expect(mapsService.createEmptyMap).toHaveBeenCalledWith( + rootNode, + undefined + ) + expect(response).toEqual(result) + }) + + it('should create a new map with a specified pid', async () => { + const pid = 'test-person-id' + + const newMap: MmpMap = createMmpMap({ ownerExternalId: pid }) + const exportedMap: IMmpClientMap = createMmpClientMap({ uuid: newMap.id }) + + const result: IMmpClientPrivateMap = { + map: exportedMap, + adminId: 'admin-id', + modificationSecret: 'modification-secret', + } + + const rootNode = createClientRootNode() + + jest.spyOn(mapsService, 'createEmptyMap').mockResolvedValueOnce(newMap) + jest + .spyOn(mapsService, 'exportMapToClient') + .mockResolvedValueOnce(exportedMap) + + const response = await mapsController.create({ rootNode }, { + pid, + } as Request) + + expect(mapsService.createEmptyMap).toHaveBeenCalledWith(rootNode, pid) expect(response).toEqual(result) }) }) diff --git a/teammapper-backend/src/map/controllers/maps.controller.ts b/teammapper-backend/src/map/controllers/maps.controller.ts index f29b4a118..409e44b9c 100644 --- a/teammapper-backend/src/map/controllers/maps.controller.ts +++ b/teammapper-backend/src/map/controllers/maps.controller.ts @@ -1,5 +1,6 @@ import { Body, + Req, Controller, Get, Delete, @@ -13,7 +14,9 @@ import { IMmpClientDeleteRequest, IMmpClientMap, IMmpClientMapCreateRequest, + IMmpClientMapInfo, IMmpClientPrivateMap, + Request, } from '../types' import MalformedUUIDError from '../services/uuid.error' import { EntityNotFoundError } from 'typeorm' @@ -41,6 +44,15 @@ export default class MapsController { } } + @Get() + async findAll(@Req() req?: Request): Promise { + if (!req) return [] + const pid = req.pid + if (!pid) return [] + const maps = await this.mapsService.getMapsOfUser(pid) + return maps + } + @Delete(':id') async delete( @Param('id') mapId: string, @@ -53,9 +65,13 @@ export default class MapsController { @Post() async create( - @Body() body: IMmpClientMapCreateRequest + @Body() body: IMmpClientMapCreateRequest, + @Req() req?: Request ): Promise { - const newMap = await this.mapsService.createEmptyMap(body.rootNode) + const pid = req?.pid + + const newMap = await this.mapsService.createEmptyMap(body.rootNode, pid) + const exportedMap = await this.mapsService.exportMapToClient(newMap.id) if (exportedMap) { diff --git a/teammapper-backend/src/map/controllers/maps.gateway.spec.ts b/teammapper-backend/src/map/controllers/maps.gateway.spec.ts index b17fd4687..09c519981 100644 --- a/teammapper-backend/src/map/controllers/maps.gateway.spec.ts +++ b/teammapper-backend/src/map/controllers/maps.gateway.spec.ts @@ -9,7 +9,7 @@ import { MapsService } from '../services/maps.service' import { MapsGateway } from './maps.gateway' import { MmpNode } from '../entities/mmpNode.entity' import { createMock } from '@golevelup/ts-jest' -import { IMmpClientNode } from '../types' +import { IMmpClientNode, OperationResponse } from '../types' const crypto = require('crypto') // eslint-disable-line @typescript-eslint/no-require-imports @@ -94,7 +94,7 @@ describe('WebSocketGateway', () => { }) describe('addNode', () => { - it(`will return false if no new nodes are being added`, (done) => { + it(`will return error response if no new nodes are being added`, (done) => { socket = io('http://localhost:3000') socket.emit( @@ -104,8 +104,11 @@ describe('WebSocketGateway', () => { modificationSecret: map.modificationSecret, nodes: [{}], }, - (result: boolean) => { - expect(result).toEqual(false) + (result: OperationResponse) => { + expect(result.success).toEqual(false) + if (!result.success) { + expect(result.errorType).toEqual('validation') + } done() } ) @@ -116,15 +119,22 @@ describe('WebSocketGateway', () => { it(`allows request when modification secret is set`, (done) => { socket = io('http://localhost:3000') + const mockNode = new MmpNode() + mockNode.id = crypto.randomUUID() + mockNode.name = 'Test' + + jest.spyOn(mapsService, 'updateNode').mockResolvedValueOnce(mockNode) + socket.emit( 'updateNode', { mapId: map.id, modificationSecret: map.modificationSecret, - node: {}, + node: { id: mockNode.id, name: 'Test' }, + updatedProperty: 'name', }, - (result: boolean) => { - expect(result).toEqual(true) + (result: OperationResponse) => { + expect(result.success).toEqual(true) done() } ) @@ -137,6 +147,7 @@ describe('WebSocketGateway', () => { // Date objects are serialised to JSON in the result, so we'll need to be explicit in setting these here const defaultNode = { + id: crypto.randomUUID(), createdAt: new Date('2021-01-31T00:00:00.000Z').toISOString(), lastModified: new Date('2021-01-31T00:00:00.000Z').toISOString(), } @@ -148,8 +159,8 @@ describe('WebSocketGateway', () => { modificationSecret: map.modificationSecret, node: defaultNode, }, - (result: MmpNode | undefined) => { - expect(result).toEqual(defaultNode) + (result: OperationResponse) => { + expect(result.success).toEqual(true) done() } ) @@ -197,8 +208,11 @@ describe('WebSocketGateway', () => { diff, modificationSecret: map.modificationSecret, }, - (result: boolean) => { - expect(result).toEqual(true) + (result: OperationResponse) => { + expect(result.success).toEqual(true) + if (result.success) { + expect(result.data).toEqual(diff) + } done() } ) @@ -225,7 +239,7 @@ describe('WebSocketGateway', () => { }) describe('error handling in gateway methods', () => { - it('addNodes returns false when service throws error', (done) => { + it('addNodes returns CriticalErrorResponse when service throws error', (done) => { socket = io('http://localhost:3000') // Mock service to throw error @@ -246,14 +260,17 @@ describe('WebSocketGateway', () => { }, ], }, - (result: boolean) => { - expect(result).toEqual(false) + (result: OperationResponse) => { + expect(result.success).toEqual(false) + if (!result.success) { + expect(result.errorType).toEqual('critical') + } done() } ) }) - it('updateNode returns false when service throws error', (done) => { + it('updateNode returns CriticalErrorResponse when service throws error', (done) => { socket = io('http://localhost:3000') // Mock service to throw error @@ -271,15 +288,19 @@ describe('WebSocketGateway', () => { name: 'test', coordinates: { x: 1, y: 2 }, }, + updatedProperty: 'name', }, - (result: boolean) => { - expect(result).toEqual(false) + (result: OperationResponse) => { + expect(result.success).toEqual(false) + if (!result.success) { + expect(result.errorType).toEqual('critical') + } done() } ) }) - it('applyMapChangesByDiff returns false when service throws error', (done) => { + it('applyMapChangesByDiff returns CriticalErrorResponse when service throws error', (done) => { socket = io('http://localhost:3000') // Mock service to throw error @@ -298,8 +319,12 @@ describe('WebSocketGateway', () => { deleted: {}, }, }, - (result: boolean) => { - expect(result).toEqual(false) + (result: OperationResponse) => { + expect(result.success).toEqual(false) + if (!result.success) { + expect(result.errorType).toEqual('critical') + expect(result.code).toEqual('SERVER_ERROR') + } done() } ) @@ -331,6 +356,316 @@ describe('WebSocketGateway', () => { }) }) + describe('addNodes - additional OperationResponse handling', () => { + it('returns SuccessResponse on successful node addition', (done) => { + socket = io('http://localhost:3000') + + const mockNode = new MmpNode() + mockNode.id = crypto.randomUUID() + mockNode.nodeMapId = map.id + mockNode.name = 'Test Node' + + jest + .spyOn(mapsService, 'addNodesFromClient') + .mockResolvedValueOnce([mockNode]) + + socket.emit( + 'addNodes', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + nodes: [ + { + id: mockNode.id, + name: 'Test Node', + coordinates: { x: 1, y: 2 }, + isRoot: true, + }, + ], + }, + (result: OperationResponse) => { + expect(result.success).toBe(true) + if (result.success) { + expect(result.data).toBeDefined() + expect(Array.isArray(result.data)).toBe(true) + expect(result.data.length).toBe(1) + } + done() + } + ) + }) + + it('returns ValidationErrorResponse when validation fails', (done) => { + socket = io('http://localhost:3000') + + jest.spyOn(mapsService, 'addNodesFromClient').mockResolvedValueOnce([]) + + socket.emit( + 'addNodes', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + nodes: [ + { + id: crypto.randomUUID(), + name: 'Invalid Node', + coordinates: { x: 1, y: 2 }, + }, + ], + }, + (result: OperationResponse) => { + expect(result.success).toBe(false) + if (!result.success) { + expect(result.errorType).toBe('validation') + expect(result.code).toBe('CONSTRAINT_VIOLATION') + } + done() + } + ) + }) + + it('does not broadcast when validation error occurs', (done) => { + socket = io('http://localhost:3000') + + jest.spyOn(mapsService, 'addNodesFromClient').mockResolvedValueOnce([]) + + socket.emit( + 'addNodes', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + nodes: [ + { + id: crypto.randomUUID(), + name: 'Invalid Node', + coordinates: { x: 1, y: 2 }, + }, + ], + }, + (result: OperationResponse) => { + expect(result.success).toBe(false) + // Validation errors should not result in broadcast + if (!result.success) { + expect(result.errorType).toBe('validation') + } + done() + } + ) + }) + + it('atomic operation: if one node fails, no nodes are created', (done) => { + socket = io('http://localhost:3000') + + // Mock service to return a validation error (atomic failure) + const validationError = { + success: false as const, + errorType: 'validation' as const, + code: 'INVALID_PARENT' as const, + message: 'VALIDATION_ERROR.INVALID_PARENT', + } + + jest + .spyOn(mapsService, 'addNodesFromClient') + .mockResolvedValueOnce([validationError]) + + // Mock exportMapToClient to return a valid map for fullMapState + jest.spyOn(mapsService, 'exportMapToClient').mockResolvedValueOnce({ + uuid: map.id, + data: [], + options: { + fontMaxSize: 24, + fontMinSize: 10, + fontIncrement: 2, + }, + deletedAt: new Date(), + deleteAfterDays: 30, + lastModified: new Date(), + lastAccessed: new Date(), + createdAt: new Date(), + }) + + socket.emit( + 'addNodes', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + nodes: [ + { + id: crypto.randomUUID(), + name: 'Valid Node 1', + coordinates: { x: 1, y: 2 }, + isRoot: true, + }, + { + id: crypto.randomUUID(), + name: 'Invalid Node - Bad Parent', + coordinates: { x: 2, y: 3 }, + parent: 'nonexistent-parent', + }, + { + id: crypto.randomUUID(), + name: 'Valid Node 2', + coordinates: { x: 3, y: 4 }, + isRoot: false, + }, + ], + }, + (result: OperationResponse) => { + // The entire operation should fail + expect(result.success).toBe(false) + if (!result.success) { + expect(result.errorType).toBe('validation') + expect(result.code).toBe('INVALID_PARENT') + // Should include full map state for recovery + expect(result.fullMapState).toBeDefined() + } + done() + } + ) + }) + }) + + describe('updateNode - additional OperationResponse handling', () => { + it('returns SuccessResponse on successful node update', (done) => { + socket = io('http://localhost:3000') + + const mockNode = new MmpNode() + mockNode.id = crypto.randomUUID() + mockNode.nodeMapId = map.id + mockNode.name = 'Updated Node' + + jest.spyOn(mapsService, 'updateNode').mockResolvedValueOnce(mockNode) + + socket.emit( + 'updateNode', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + node: { + id: mockNode.id, + name: 'Updated Node', + coordinates: { x: 1, y: 2 }, + }, + updatedProperty: 'name', + }, + (result: OperationResponse) => { + expect(result.success).toBe(true) + if (result.success) { + expect(result.data).toBeDefined() + expect(result.data.id).toBe(mockNode.id) + } + done() + } + ) + }) + + it('returns ValidationErrorResponse when service returns validation error', (done) => { + socket = io('http://localhost:3000') + + const validationError = { + success: false as const, + errorType: 'validation' as const, + code: 'INVALID_PARENT' as const, + message: 'VALIDATION_ERROR.INVALID_PARENT', + } + + jest + .spyOn(mapsService, 'updateNode') + .mockResolvedValueOnce(validationError) + + socket.emit( + 'updateNode', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + node: { + id: crypto.randomUUID(), + name: 'Test', + coordinates: { x: 1, y: 2 }, + parent: 'invalid-parent', + }, + updatedProperty: 'parent', + }, + (result: OperationResponse) => { + expect(result.success).toBe(false) + if (!result.success) { + expect(result.errorType).toBe('validation') + expect(result.code).toBe('INVALID_PARENT') + } + done() + } + ) + }) + + it('does not broadcast when validation error occurs', (done) => { + socket = io('http://localhost:3000') + + const nodeId = crypto.randomUUID() + const validationError = { + success: false as const, + errorType: 'validation' as const, + code: 'INVALID_PARENT' as const, + message: 'VALIDATION_ERROR.INVALID_PARENT', + } + + jest + .spyOn(mapsService, 'updateNode') + .mockResolvedValueOnce(validationError) + + socket.emit( + 'updateNode', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + node: { + id: nodeId, + name: 'Test', + coordinates: { x: 1, y: 2 }, + }, + updatedProperty: 'name', + }, + (result: OperationResponse) => { + expect(result.success).toBe(false) + // Validation errors should not result in broadcast + if (!result.success) { + expect(result.errorType).toBe('validation') + } + done() + } + ) + }) + + it('returns CriticalErrorResponse when service throws error', (done) => { + socket = io('http://localhost:3000') + + jest + .spyOn(mapsService, 'updateNode') + .mockRejectedValueOnce(new Error('Server error')) + + socket.emit( + 'updateNode', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + node: { + id: crypto.randomUUID(), + name: 'Test', + coordinates: { x: 1, y: 2 }, + }, + updatedProperty: 'name', + }, + (result: OperationResponse) => { + expect(result.success).toBe(false) + if (!result.success) { + expect(result.errorType).toBe('critical') + expect(result.code).toBe('SERVER_ERROR') + } + done() + } + ) + }) + }) + afterEach(async () => { socket.close() jest.restoreAllMocks() diff --git a/teammapper-backend/src/map/controllers/maps.gateway.ts b/teammapper-backend/src/map/controllers/maps.gateway.ts index 95b212441..35dc25b92 100644 --- a/teammapper-backend/src/map/controllers/maps.gateway.ts +++ b/teammapper-backend/src/map/controllers/maps.gateway.ts @@ -1,7 +1,5 @@ -import { Inject, UseGuards, Logger } from '@nestjs/common' import { CACHE_MANAGER } from '@nestjs/cache-manager' -import { Cache } from 'cache-manager' -import { randomBytes } from 'crypto' +import { Inject, Logger, UseGuards } from '@nestjs/common' import { ConnectedSocket, MessageBody, @@ -10,7 +8,13 @@ import { WebSocketGateway, WebSocketServer, } from '@nestjs/websockets' +import { Cache } from 'cache-manager' +import { randomBytes } from 'crypto' import { Server, Socket } from 'socket.io' +import { QueryFailedError } from 'typeorm' +import { MmpMap } from '../entities/mmpMap.entity' +import { MmpNode } from '../entities/mmpNode.entity' +import { EditGuard } from '../guards/edit.guard' import { MapsService } from '../services/maps.service' import { IClientCache, @@ -18,17 +22,21 @@ import { IMmpClientEditingRequest, IMmpClientJoinRequest, IMmpClientMap, + IMmpClientMapDiff, IMmpClientMapRequest, + IMmpClientNode, IMmpClientNodeAddRequest, IMmpClientNodeRequest, IMmpClientNodeSelectionRequest, IMmpClientUndoRedoRequest, IMmpClientUpdateMapOptionsRequest, + OperationResponse, + ValidationErrorResponse, } from '../types' -import { mapMmpNodeToClient } from '../utils/clientServerMapping' -import { MmpMap } from '../entities/mmpMap.entity' -import { MmpNode } from '../entities/mmpNode.entity' -import { EditGuard } from '../guards/edit.guard' +import { + mapClientNodeToMmpNode, + mapMmpNodeToClient, +} from '../utils/clientServerMapping' // For possible configuration options please see: // https://socket.io/docs/v4/server-initialization/ @@ -38,6 +46,7 @@ export class MapsGateway implements OnGatewayDisconnect { server: Server private readonly logger = new Logger(MapsService.name) + private readonly CACHE_TTL_MS = 10000 constructor( private mapsService: MapsService, @@ -71,11 +80,9 @@ export class MapsGateway implements OnGatewayDisconnect { return } - client.join(request.mapId) - this.cacheManager.set(client.id, request.mapId, 10000) - const updatedClientCache: IClientCache = await this.addClientForMap( + const updatedClientCache = await this.setupClientRoomMembership( + client, request.mapId, - client.id, request.color ) @@ -153,34 +160,56 @@ export class MapsGateway implements OnGatewayDisconnect { async addNode( @ConnectedSocket() client: Socket, @MessageBody() request: IMmpClientNodeAddRequest - ): Promise { + ): Promise> { try { - const newNodes = await this.mapsService.addNodesFromClient( + const results = await this.mapsService.addNodesFromClient( request.mapId, request.nodes ) - if (!newNodes || newNodes.length === 0) return false - this.server.to(request.mapId).emit('nodesAdded', { - clientId: client.id, - nodes: newNodes.map((newNode) => mapMmpNodeToClient(newNode)), - }) + const processedResults = await this.processAddNodeResults( + results, + request.mapId + ) - // when pasting (inserting multiple nodes), do not update selection - if (newNodes.length === 1) { - this.server.to(request.mapId).emit('selectionUpdated', { - clientId: client.id, - nodeId: newNodes[newNodes.length - 1]?.id, - selected: true, - }) + if ('success' in processedResults) { + return processedResults } - return true + if ('validationError' in processedResults) { + const fullMapState = await this.safeExportMapToClient(request.mapId) + return { + ...processedResults.validationError, + fullMapState, + } as OperationResponse + } + + const { successfulNodes } = processedResults + this.broadcastSuccessfulNodeAddition( + request.mapId, + client.id, + successfulNodes + ) + + const clientNodes = successfulNodes.map((node) => + mapMmpNodeToClient(node) + ) + return this.buildSuccessResponse(clientNodes) } catch (error) { - this.logger.error( - `Failed to add nodes: ${error instanceof Error ? error.message : String(error)}` + if (error instanceof QueryFailedError) { + const mmpNode = mapClientNodeToMmpNode(request.nodes[0], request.mapId) + return this.handleDatabaseConstraintError( + error, + mmpNode as MmpNode, + request.mapId + ) + } + + return this.handleUnexpectedOperationError( + error, + request.mapId, + 'Failed to add nodes' ) - return false } } @@ -189,29 +218,56 @@ export class MapsGateway implements OnGatewayDisconnect { async updateNode( @ConnectedSocket() client: Socket, @MessageBody() request: IMmpClientNodeRequest - ): Promise { + ): Promise> { try { - if (!request.node) return false + if (!request.node) { + return this.buildErrorResponse( + 'validation', + 'MISSING_REQUIRED_FIELD', + 'VALIDATION_ERROR.MISSING_REQUIRED_FIELD', + request.mapId + ) + } const updatedNode = await this.mapsService.updateNode( request.mapId, request.node ) - if (!updatedNode) return false + const processedResult = await this.handleNodeUpdateResult( + updatedNode ?? null, + request.mapId + ) - this.server.to(request.mapId).emit('nodeUpdated', { + if ('success' in processedResult) { + return processedResult + } + + const { validNode } = processedResult + const clientNode = mapMmpNodeToClient(validNode) + + this.broadcastToRoom(request.mapId, 'nodeUpdated', { clientId: client.id, property: request.updatedProperty, - node: mapMmpNodeToClient(updatedNode), + node: clientNode, }) - return true + return this.buildSuccessResponse(clientNode) } catch (error) { - this.logger.error( - `Failed to update node: ${error instanceof Error ? error.message : String(error)}` + if (error instanceof QueryFailedError) { + const mmpNode = mapClientNodeToMmpNode(request.node, request.mapId) + return this.handleDatabaseConstraintError( + error, + mmpNode as MmpNode, + request.mapId + ) + } + + return this.handleUnexpectedOperationError( + error, + request.mapId, + 'Failed to update node' ) - return false } } @@ -220,23 +276,40 @@ export class MapsGateway implements OnGatewayDisconnect { async applyMapChangesByDiff( @ConnectedSocket() client: Socket, @MessageBody() request: IMmpClientUndoRedoRequest - ): Promise { + ): Promise> { try { - if (!(await this.mapsService.findMap(request.mapId))) return false - if (!request.diff) return false + if (!(await this.mapsService.findMap(request.mapId))) { + return this.buildErrorResponse( + 'critical', + 'MALFORMED_REQUEST', + 'CRITICAL_ERROR.MAP_NOT_FOUND', + request.mapId + ) + } + + if (!request.diff) { + return this.buildErrorResponse( + 'critical', + 'MALFORMED_REQUEST', + 'CRITICAL_ERROR.MISSING_REQUIRED_FIELD', + request.mapId + ) + } await this.mapsService.updateMapByDiff(request.mapId, request.diff) - this.server - .to(request.mapId) - .emit('mapChangesUndoRedo', { clientId: client.id, diff: request.diff }) + this.broadcastToRoom(request.mapId, 'mapChangesUndoRedo', { + clientId: client.id, + diff: request.diff, + }) - return true + return this.buildSuccessResponse(request.diff) } catch (error) { - this.logger.error( - `Failed to apply map changes by diff: ${error instanceof Error ? error.message : String(error)}` + return this.handleUnexpectedOperationError( + error, + request.mapId, + 'Failed to apply map changes by diff' ) - return false } } @@ -251,32 +324,28 @@ export class MapsGateway implements OnGatewayDisconnect { const mmpMap: IMmpClientMap = request.map - // Disconnect all clients temporarily - // Emit an event so clients can display a notification - this.server.to(mmpMap.uuid).emit('clientNotification', { + this.broadcastToRoom(mmpMap.uuid, 'clientNotification', { clientId: client.id, message: 'TOASTS.WARNINGS.MAP_IMPORT_IN_PROGRESS', type: 'warning', }) - const sockets = await this.server.in(request.mapId).fetchSockets() - this.server.in(request.mapId).socketsLeave(request.mapId) + const sockets = await this.disconnectAllClientsFromMap(request.mapId) await this.mapsService.updateMap(mmpMap) - // Reconnect clients once map is updated - sockets.forEach((socket) => { - // socketsJoin() doesn't work here as the sockets have left the room and this.server.in(request.mapId) would return nothing - socket.join(request.mapId) - }) + this.reconnectClientsToMap(sockets, request.mapId) const exportMap = await this.mapsService.exportMapToClient(mmpMap.uuid) - this.server - .to(mmpMap.uuid) - .emit('mapUpdated', { clientId: client.id, map: exportMap }) + if (exportMap) { + this.broadcastToRoom(mmpMap.uuid, 'mapUpdated', { + clientId: client.id, + map: exportMap, + }) + } - this.server.to(mmpMap.uuid).emit('clientNotification', { + this.broadcastToRoom(mmpMap.uuid, 'clientNotification', { clientId: client.id, message: 'TOASTS.MAP_IMPORT_SUCCESS', type: 'success', @@ -296,22 +365,43 @@ export class MapsGateway implements OnGatewayDisconnect { async removeNode( @ConnectedSocket() client: Socket, @MessageBody() request: IMmpClientNodeRequest - ): Promise { + ): Promise> { try { - const removedNode: MmpNode | undefined = - await this.mapsService.removeNode(request.node, request.mapId) + if (!this.hasRequiredNodeFields(request.node)) { + return this.buildErrorResponse( + 'critical', + 'MALFORMED_REQUEST', + 'CRITICAL_ERROR.MISSING_REQUIRED_FIELD', + request.mapId + ) + } + + const removedNode = await this.mapsService.removeNode( + request.node, + request.mapId + ) - this.server.to(request.mapId).emit('nodeRemoved', { + if (!removedNode) { + return this.buildErrorResponse( + 'critical', + 'MALFORMED_REQUEST', + 'CRITICAL_ERROR.NODE_NOT_FOUND', + request.mapId + ) + } + + this.broadcastToRoom(request.mapId, 'nodeRemoved', { clientId: client.id, - nodeId: request?.node?.id, + nodeId: request.node.id, }) - return removedNode + return this.buildSuccessResponse(mapMmpNodeToClient(removedNode)) } catch (error) { - this.logger.error( - `Failed to remove node: ${error instanceof Error ? error.message : String(error)}` + return this.handleUnexpectedOperationError( + error, + request.mapId, + 'Failed to remove node' ) - return undefined } } @@ -329,28 +419,43 @@ export class MapsGateway implements OnGatewayDisconnect { return true } + /** + * Updates client cache for a map with a transformation function + * @param mapId - The map ID + * @param updateFn - Function to transform the cache + * @returns The updated cache + */ + private async updateClientCache( + mapId: string, + updateFn: (cache: IClientCache) => IClientCache + ): Promise { + const currentCache: IClientCache = + (await this.cacheManager.get(mapId)) || {} + const updatedCache = updateFn(currentCache) + await this.cacheManager.set(mapId, updatedCache, this.CACHE_TTL_MS) + return updatedCache + } + private async addClientForMap( mapId: string, clientId: string, color: string ): Promise { - const currentClientCache: IClientCache = - (await this.cacheManager.get(mapId)) || {} - const overwriteColor = this.chooseColor(currentClientCache, color) - - const newClientCache: IClientCache = { - ...currentClientCache, - [clientId]: overwriteColor, - } - await this.cacheManager.set(mapId, newClientCache, 10000) - return newClientCache + return this.updateClientCache(mapId, (cache) => ({ + ...cache, + [clientId]: this.chooseColor(cache, color), + })) } - private async removeClientForMap(mapId: string, clientId: string) { - const currentClientCache: IClientCache = - (await this.cacheManager.get(mapId)) || {} - delete currentClientCache[clientId] - this.cacheManager.set(mapId, currentClientCache, 10000) + private async removeClientForMap( + mapId: string, + clientId: string + ): Promise { + return this.updateClientCache(mapId, (cache) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { [clientId]: _, ...rest } = cache + return rest + }) } private chooseColor(currentClientCache: IClientCache, color: string): string { @@ -360,4 +465,305 @@ export class MapsGateway implements OnGatewayDisconnect { return color } + + /** + * Safely exports map to client with error handling + * Returns undefined if export fails (e.g., database unavailable) + */ + private async safeExportMapToClient( + mapId: string + ): Promise { + try { + return await this.mapsService.exportMapToClient(mapId) + } catch (exportError) { + this.logger.error( + `Failed to export map state for error recovery: ${exportError instanceof Error ? exportError.message : String(exportError)}` + ) + return undefined + } + } + + // ============================================================ + // Error Handling Helpers + // ============================================================ + + /** + * Creates a validation error response with full map state for client recovery + */ + private async buildErrorResponse( + errorType: 'validation', + code: + | 'INVALID_PARENT' + | 'CONSTRAINT_VIOLATION' + | 'MISSING_REQUIRED_FIELD' + | 'CIRCULAR_REFERENCE' + | 'DUPLICATE_NODE', + message: string, + mapId: string + ): Promise> + + /** + * Creates a critical error response with full map state for client recovery + */ + private async buildErrorResponse( + errorType: 'critical', + code: + | 'SERVER_ERROR' + | 'NETWORK_TIMEOUT' + | 'AUTH_FAILED' + | 'MALFORMED_REQUEST' + | 'RATE_LIMIT_EXCEEDED', + message: string, + mapId: string + ): Promise> + + /** + * Implementation of error response builder + */ + private async buildErrorResponse( + errorType: 'validation' | 'critical', + code: string, + message: string, + mapId: string + ): Promise> { + const fullMapState = await this.safeExportMapToClient(mapId) + return { + success: false, + errorType, + code, + message, + fullMapState, + } as OperationResponse + } + + /** + * Handles database constraint errors and converts them to validation responses + */ + private async handleDatabaseConstraintError( + error: QueryFailedError, + node: MmpNode, + mapId: string + ): Promise> { + const validationResponse = + await this.mapsService.mapConstraintErrorToValidationResponse( + error, + node, + mapId + ) + const fullMapState = await this.safeExportMapToClient(mapId) + return { + ...validationResponse, + fullMapState, + } as OperationResponse + } + + /** + * Handles unexpected errors during operations and creates appropriate error response + */ + private async handleUnexpectedOperationError( + error: unknown, + mapId: string, + operationContext: string + ): Promise> { + this.logger.error( + `${operationContext}: ${error instanceof Error ? error.message : String(error)}` + ) + return this.buildErrorResponse( + 'critical', + 'SERVER_ERROR', + 'CRITICAL_ERROR.SERVER_UNAVAILABLE', + mapId + ) + } + + // ============================================================ + // Response Building Helpers + // ============================================================ + + /** + * Creates a successful operation response with data + */ + private buildSuccessResponse(data: T): OperationResponse { + return { + success: true, + data, + } + } + + /** + * Extracts validation errors from a mixed array of results + */ + private extractValidationErrors( + results: (MmpNode | ValidationErrorResponse)[] + ): ValidationErrorResponse[] { + return results.filter( + (r) => 'errorType' in r && r.errorType === 'validation' + ) as ValidationErrorResponse[] + } + + /** + * Checks if a result is a validation error response + */ + private isValidationError( + result: MmpNode | ValidationErrorResponse + ): result is ValidationErrorResponse { + return 'errorType' in result && result.errorType === 'validation' + } + + // ============================================================ + // Broadcasting Helpers + // ============================================================ + + /** + * Generic method to broadcast events to all clients in a map room + * @param mapId - The map room ID + * @param eventName - The socket event name to emit + * @param payload - The event payload (can include clientId and any other data) + */ + private broadcastToRoom>( + mapId: string, + eventName: string, + payload: T + ): void { + this.server.to(mapId).emit(eventName, payload) + } + + // ============================================================ + // AddNode Operation Helpers + // ============================================================ + + /** + * Processes results from adding nodes (atomic operation) + * Returns appropriate response - either all nodes succeeded or operation failed + */ + private async processAddNodeResults( + results: (MmpNode | ValidationErrorResponse)[] | null, + mapId: string + ): Promise< + | OperationResponse + | { validationError: ValidationErrorResponse } + | { successfulNodes: MmpNode[] } + > { + if (!results || results.length === 0) { + return this.buildErrorResponse( + 'validation', + 'CONSTRAINT_VIOLATION', + 'VALIDATION_ERROR.CONSTRAINT_VIOLATION', + mapId + ) + } + + // Check if the result is a single validation error (atomic failure) + if (results.length === 1 && this.isValidationError(results[0])) { + return { validationError: results[0] } + } + + // All results are successful MmpNodes (atomic success) + return { successfulNodes: results as MmpNode[] } + } + + /** + * Handles successful node addition by broadcasting and updating selection + */ + private broadcastSuccessfulNodeAddition( + mapId: string, + clientId: string, + nodes: MmpNode[] + ): void { + const clientNodes = nodes.map((node) => mapMmpNodeToClient(node)) + this.broadcastToRoom(mapId, 'nodesAdded', { clientId, nodes: clientNodes }) + + if (nodes.length === 1 && nodes[0]?.id) { + this.broadcastToRoom(mapId, 'selectionUpdated', { + clientId, + nodeId: nodes[0].id, + selected: true, + }) + } + } + + // ============================================================ + // UpdateNode Operation Helpers + // ============================================================ + + /** + * Processes the result of a node update operation + */ + private async handleNodeUpdateResult( + result: MmpNode | ValidationErrorResponse | null, + mapId: string + ): Promise | { validNode: MmpNode }> { + if (!result) { + return this.buildErrorResponse( + 'validation', + 'INVALID_PARENT', + 'VALIDATION_ERROR.INVALID_PARENT', + mapId + ) + } + + if (this.isValidationError(result)) { + return { + ...result, + fullMapState: await this.safeExportMapToClient(mapId), + } + } + + return { validNode: result as MmpNode } + } + + // ============================================================ + // RemoveNode Operation Helpers + // ============================================================ + + /** + * Validates node removal request has required fields + */ + private hasRequiredNodeFields( + node: IMmpClientNode | undefined + ): node is IMmpClientNode & { id: string } { + return !!node && !!node.id + } + + // ============================================================ + // UpdateMap Operation Helpers + // ============================================================ + + /** + * Temporarily disconnects all clients from a map room before major update + */ + private async disconnectAllClientsFromMap(mapId: string) { + const sockets = await this.server.in(mapId).fetchSockets() + this.server.in(mapId).socketsLeave(mapId) + return sockets + } + + /** + * Reconnects previously disconnected clients back to the map room + */ + private reconnectClientsToMap( + sockets: Awaited>, + mapId: string + ): void { + sockets.forEach((socket) => { + socket.join(mapId) + }) + } + + // ============================================================ + // OnJoin Operation Helpers + // ============================================================ + + /** + * Sets up client room membership and updates cache + */ + private async setupClientRoomMembership( + client: Socket, + mapId: string, + color: string + ): Promise { + client.join(mapId) + this.cacheManager.set(client.id, mapId, this.CACHE_TTL_MS) + return await this.addClientForMap(mapId, client.id, color) + } } diff --git a/teammapper-backend/src/map/entities/mmpMap.entity.ts b/teammapper-backend/src/map/entities/mmpMap.entity.ts index 8f22d1238..c4af95bbc 100644 --- a/teammapper-backend/src/map/entities/mmpMap.entity.ts +++ b/teammapper-backend/src/map/entities/mmpMap.entity.ts @@ -27,6 +27,9 @@ export class MmpMap { @Generated('uuid') adminId: string | null + @Column({ type: 'varchar', nullable: true }) + ownerExternalId?: string | null + @Column({ type: 'uuid', nullable: true, default: null }) @Generated('uuid') modificationSecret: string | null diff --git a/teammapper-backend/src/map/map.module.ts b/teammapper-backend/src/map/map.module.ts index b87a75d04..39709a144 100644 --- a/teammapper-backend/src/map/map.module.ts +++ b/teammapper-backend/src/map/map.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common' +import { MiddlewareConsumer, Module } from '@nestjs/common' import { CacheModule } from '@nestjs/cache-manager' import { ScheduleModule } from '@nestjs/schedule' import { TypeOrmModule } from '@nestjs/typeorm' @@ -10,6 +10,8 @@ import { MapsService } from './services/maps.service' import { TasksService } from './services/tasks.service' import MermaidController from './controllers/mermaid.controller' import { AiService } from './services/ai.service' +import cookieParser from 'cookie-parser' +import { PersonIdMiddleware } from '../auth/person-id.middleware' @Module({ imports: [ @@ -21,4 +23,10 @@ import { AiService } from './services/ai.service' providers: [MapsService, MapsGateway, TasksService, AiService], exports: [MapsService], }) -export class MapModule {} +export class MapModule { + configure(consumer: MiddlewareConsumer) { + consumer + .apply(cookieParser(), new PersonIdMiddleware().use) + .forRoutes('api/maps') + } +} diff --git a/teammapper-backend/src/map/services/maps.service.spec.ts b/teammapper-backend/src/map/services/maps.service.spec.ts index a5ab6e107..23779358b 100644 --- a/teammapper-backend/src/map/services/maps.service.spec.ts +++ b/teammapper-backend/src/map/services/maps.service.spec.ts @@ -4,7 +4,7 @@ import { getRepositoryToken, TypeOrmModule } from '@nestjs/typeorm' import { Logger } from '@nestjs/common' import { MmpMap } from '../entities/mmpMap.entity' import { MmpNode } from '../entities/mmpNode.entity' -import { Repository } from 'typeorm' +import { Repository, QueryFailedError } from 'typeorm' import { ConfigModule } from '@nestjs/config' import AppModule from '../../app.module' import { @@ -79,6 +79,8 @@ describe('MapsService', () => { nodeMapId: map.id, coordinatesX: 3, coordinatesY: 1, + root: false, + detached: true, }) await mapsService.addNodes(map.id, [node]) @@ -105,7 +107,14 @@ describe('MapsService', () => { const nodes = await mapsService.addNodes(map.id, [node]) - expect(nodes).toEqual([]) + // Now returns ValidationErrorResponse instead of empty array + expect(Array.isArray(nodes)).toBe(true) + expect(nodes).toHaveLength(1) + if ('errorType' in nodes[0]) { + expect(nodes[0].success).toBe(false) + expect(nodes[0].errorType).toBe('validation') + expect(nodes[0].code).toBe('CONSTRAINT_VIOLATION') + } expect(loggerSpyWarn).toHaveBeenCalled() }) @@ -124,7 +133,14 @@ describe('MapsService', () => { const nodes = await mapsService.addNodes(map.id, [node]) - expect(nodes).toEqual([]) + // Now returns ValidationErrorResponse instead of empty array + expect(Array.isArray(nodes)).toBe(true) + expect(nodes).toHaveLength(1) + if ('errorType' in nodes[0]) { + expect(nodes[0].success).toBe(false) + expect(nodes[0].errorType).toBe('validation') + expect(nodes[0].code).toBe('CONSTRAINT_VIOLATION') + } expect(loggerSpyWarn).toHaveBeenCalledWith( expect.stringContaining('Detached node') ) @@ -133,30 +149,41 @@ describe('MapsService', () => { it('catches an FK error when trying to assign a nodeParentId from a different map', async () => { const map = await mapsRepo.save({}) const mapTwo = await mapsRepo.save({}) - const loggerSpyWarn = jest.spyOn(Logger.prototype, 'warn') - const parentNode = await nodesRepo.create({ + // First add parent node to map + const parentNode = await nodesRepo.save({ id: '2177d542-665d-468c-bea5-7520bdc5b481', nodeMapId: map.id, coordinatesX: 2, coordinatesY: 1, + root: true, + detached: false, }) + // Try to add child node to mapTwo that references parent in map const childNodeFromDifferentMap = await nodesRepo.create({ id: 'cf65f9cc-0050-4e23-ac4d-effb61cb1731', nodeMapId: mapTwo.id, coordinatesX: 1, coordinatesY: 1, nodeParentId: parentNode.id, + root: false, + detached: false, }) - const nodes = await mapsService.addNodes(map.id, [ - parentNode, + const nodes = await mapsService.addNodes(mapTwo.id, [ childNodeFromDifferentMap, ]) - expect(nodes).toEqual([]) - expect(loggerSpyWarn).toHaveBeenCalled() + // Should fail with INVALID_PARENT because parent is in different map + expect(Array.isArray(nodes)).toBe(true) + expect(nodes.length).toBe(1) + expect('errorType' in nodes[0]).toBe(true) + if ('errorType' in nodes[0]) { + expect(nodes[0].success).toBe(false) + expect(nodes[0].errorType).toBe('validation') + expect(nodes[0].code).toBe('INVALID_PARENT') + } }) }) @@ -185,7 +212,7 @@ describe('MapsService', () => { ) }) - it('returns undefined when trying to update node with non-existent parent', async () => { + it('returns ValidationErrorResponse when trying to update node with non-existent parent', async () => { const map = await mapsRepo.save({}) const loggerSpyWarn = jest.spyOn(Logger.prototype, 'warn') @@ -204,7 +231,13 @@ describe('MapsService', () => { const result = await mapsService.updateNode(map.id, clientNode) - expect(result).toBeUndefined() + // Now returns ValidationErrorResponse instead of undefined + expect(result).toBeDefined() + if (result && 'errorType' in result) { + expect(result.success).toBe(false) + expect(result.errorType).toBe('validation') + expect(result.code).toBe('CONSTRAINT_VIOLATION') + } expect(loggerSpyWarn).toHaveBeenCalledWith( expect.stringContaining('Cannot update node') ) @@ -506,6 +539,18 @@ describe('MapsService', () => { expect.stringContaining('Failed to create root node') ) }) + it('creates a map with a specified userId as owner', async () => { + const testUserId = 'test-person-id' + + const newMap = await mapsService.createEmptyMap(undefined, testUserId) + + expect(newMap.ownerExternalId).toBe(testUserId) + + const savedMap = await mapsRepo.findOne({ where: { id: newMap.id } }) + + expect(savedMap).toBeDefined() + expect(savedMap?.ownerExternalId).toBe(testUserId) + }) }) describe('addNode - duplicate handling', () => { @@ -523,11 +568,15 @@ describe('MapsService', () => { const firstAdd = await mapsService.addNode(map.id, node) expect(firstAdd).not.toBeUndefined() + expect('id' in firstAdd!).toBe(true) // Try to add the same node again const secondAdd = await mapsService.addNode(map.id, node) expect(secondAdd).not.toBeUndefined() - expect(secondAdd?.id).toEqual(firstAdd?.id) + expect('id' in secondAdd!).toBe(true) + if ('id' in firstAdd! && 'id' in secondAdd!) { + expect(secondAdd.id).toEqual(firstAdd.id) + } // Verify only one node exists in database const allNodes = await nodesRepo.find({ where: { nodeMapId: map.id } }) @@ -536,37 +585,60 @@ describe('MapsService', () => { }) describe('updateMapByDiff', () => { - it('handles errors in diff callbacks gracefully', async () => { + it('rolls back all changes when any operation fails (atomic transaction)', async () => { const map = await mapsRepo.save({}) const loggerSpy = jest.spyOn(Logger.prototype, 'error') - // Mock addNodesFromClient to throw an error - jest - .spyOn(mapsService, 'addNodesFromClient') - .mockRejectedValueOnce(new Error('Validation error')) + const existingNode = await nodesRepo.save({ + id: '78a2ae85-1815-46da-a2bc-a41de6bdd5cc', + nodeMapId: map.id, + coordinatesX: 3, + coordinatesY: 1, + root: true, + name: 'Original Name', + }) - // Create a diff that will trigger the mocked error + // Create a diff with valid update but invalid add (invalid UUID will cause error) const diff = { added: { - 'some-node': { - id: 'some-node', - name: 'Test', + 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa': { + id: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa', + name: 'New Node', coordinates: { x: 1, y: 1 }, - isRoot: true, + isRoot: false, + detached: false, + // Invalid parent reference will cause transaction to fail + parent: '99999999-9999-9999-9999-999999999999', + }, + }, + updated: { + [existingNode.id]: { + name: 'Updated Name', }, }, - updated: {}, deleted: {}, } - // Should not throw, but log errors - await mapsService.updateMapByDiff(map.id, diff) + // Should throw error and roll back ALL changes (atomic behavior) + await expect(mapsService.updateMapByDiff(map.id, diff)).rejects.toThrow() - // Verify error was logged (not thrown) + // Verify error was logged expect(loggerSpy).toHaveBeenCalled() + + // Verify the update was rolled back - name should still be original + const nodeAfterRollback = await nodesRepo.findOne({ + where: { id: existingNode.id }, + }) + expect(nodeAfterRollback?.name).toEqual('Original Name') + + // Verify the new node was not added + const newNode = await nodesRepo.findOne({ + where: { id: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa' }, + }) + expect(newNode).toBeNull() }) - it('processes all diff callbacks sequentially', async () => { + it('successfully applies all changes when all operations succeed (atomic transaction)', async () => { const map = await mapsRepo.save({}) const rootNode = await nodesRepo.save({ @@ -575,56 +647,77 @@ describe('MapsService', () => { coordinatesX: 3, coordinatesY: 1, root: true, + name: 'Original Name', + }) + + const nodeToDelete = await nodesRepo.save({ + id: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb', + nodeMapId: map.id, + coordinatesX: 4, + coordinatesY: 2, + root: false, + detached: true, }) const diff = { - added: {}, + added: { + 'cccccccc-cccc-4ccc-8ccc-cccccccccccc': { + id: 'cccccccc-cccc-4ccc-8ccc-cccccccccccc', + name: 'New Node', + coordinates: { x: 5, y: 3 }, + isRoot: false, + detached: true, + }, + }, updated: { [rootNode.id]: { name: 'Updated Name', }, }, - deleted: {}, + deleted: { + [nodeToDelete.id]: {}, + }, } + // Should succeed atomically await mapsService.updateMapByDiff(map.id, diff) + // Verify update was applied const updatedNode = await nodesRepo.findOne({ where: { id: rootNode.id }, }) expect(updatedNode?.name).toEqual('Updated Name') + + // Verify node was added + const newNode = await nodesRepo.findOne({ + where: { id: 'cccccccc-cccc-4ccc-8ccc-cccccccccccc' }, + }) + expect(newNode).not.toBeNull() + expect(newNode?.name).toEqual('New Node') + + // Verify node was deleted + const deletedNode = await nodesRepo.findOne({ + where: { id: nodeToDelete.id }, + }) + expect(deletedNode).toBeNull() }) - it('continues processing after one callback fails', async () => { + it('processes updates sequentially to maintain parent-child relationships', async () => { const map = await mapsRepo.save({}) - const loggerSpy = jest.spyOn(Logger.prototype, 'error') - const validNode = await nodesRepo.save({ - id: '78a2ae85-1815-46da-a2bc-a41de6bdd5cc', + const rootNode = await nodesRepo.save({ + id: '11111111-1111-1111-1111-111111111111', nodeMapId: map.id, - coordinatesX: 3, + coordinatesX: 1, coordinatesY: 1, root: true, }) - // Mock addNodesFromClient to fail, but other operations should continue - jest - .spyOn(mapsService, 'addNodesFromClient') - .mockRejectedValueOnce(new Error('Add failed')) - - // Mix failing add with valid update const diff = { - added: { - 'some-node': { - id: 'some-node', - name: 'Test', - coordinates: { x: 1, y: 1 }, - isRoot: true, - }, - }, + added: {}, updated: { - [validNode.id]: { - name: 'Updated Successfully', + [rootNode.id]: { + name: 'Updated Root', }, }, deleted: {}, @@ -632,14 +725,239 @@ describe('MapsService', () => { await mapsService.updateMapByDiff(map.id, diff) - // Valid update should still succeed despite invalid add const updatedNode = await nodesRepo.findOne({ - where: { id: validNode.id }, + where: { id: rootNode.id }, }) - expect(updatedNode?.name).toEqual('Updated Successfully') + expect(updatedNode?.name).toEqual('Updated Root') + }) + }) - // Error should be logged for the failed operation - expect(loggerSpy).toHaveBeenCalled() + describe('mapConstraintErrorToValidationResponse', () => { + it('returns ValidationErrorResponse for invalid parent constraint', async () => { + const map = await mapsRepo.save({}) + + // Try to add a node with invalid but valid-UUID-format parent + const invalidNode = nodesRepo.create({ + id: '00000000-0000-4000-8000-000000000002', + nodeMapId: map.id, + nodeParentId: '99999999-9999-9999-9999-999999999999', + coordinatesX: 1, + coordinatesY: 1, + }) + + // This should throw a QueryFailedError + try { + await nodesRepo.save(invalidNode) + fail('Expected QueryFailedError to be thrown') + } catch (error) { + if (error instanceof Error && error.name === 'QueryFailedError') { + const response = + await mapsService.mapConstraintErrorToValidationResponse( + error as QueryFailedError, + invalidNode, + map.id + ) + + expect(response.success).toBe(false) + expect(response.errorType).toBe('validation') + expect(response.code).toBe('INVALID_PARENT') + expect(response.message).toBe('VALIDATION_ERROR.INVALID_PARENT') + } + } + }) + }) + + describe('addNode with ValidationErrorResponse', () => { + it('returns ValidationErrorResponse when addNode fails with constraint violation', async () => { + const map = await mapsRepo.save({}) + + // Create a node with invalid parent reference (valid UUID format but doesn't exist) + const nodeWithInvalidParent = nodesRepo.create({ + id: '78a2ae85-1815-46da-a2bc-a41de6bdd5cc', + nodeMapId: map.id, + nodeParentId: '99999999-9999-4999-8999-999999999999', + coordinatesX: 3, + coordinatesY: 1, + root: false, + detached: false, + }) + + const result = await mapsService.addNode(map.id, nodeWithInvalidParent) + + // Should return ValidationErrorResponse, not throw + expect(result).toBeDefined() + if (result && 'errorType' in result) { + expect(result.success).toBe(false) + expect(result.errorType).toBe('validation') + expect(result.code).toBe('INVALID_PARENT') + } + }) + }) + + describe('addNodes - atomic transaction behavior', () => { + it('rolls back all nodes if one node fails validation (atomic operation)', async () => { + const map = await mapsRepo.save({}) + + // Create a valid root node + const validRootNode = nodesRepo.create({ + id: '11111111-1111-1111-1111-111111111111', + nodeMapId: map.id, + coordinatesX: 1, + coordinatesY: 1, + root: true, + detached: false, + }) + + // Create another valid detached node + const validDetachedNode = nodesRepo.create({ + id: '22222222-2222-2222-2222-222222222222', + nodeMapId: map.id, + coordinatesX: 2, + coordinatesY: 2, + root: false, + detached: true, + }) + + // Create an invalid node with non-existent parent (valid UUID format) + const invalidNode = nodesRepo.create({ + id: '33333333-3333-4333-8333-333333333333', + nodeMapId: map.id, + coordinatesX: 3, + coordinatesY: 3, + root: false, + detached: false, + nodeParentId: '99999999-9999-4999-8999-999999999999', // Valid UUID but doesn't exist + }) + + // Try to add all three nodes at once + const result = await mapsService.addNodes(map.id, [ + validRootNode, + validDetachedNode, + invalidNode, + ]) + + // Should return a single ValidationErrorResponse + expect(Array.isArray(result)).toBe(true) + expect(result.length).toBe(1) + expect('errorType' in result[0]).toBe(true) + if ('errorType' in result[0]) { + expect(result[0].success).toBe(false) + expect(result[0].errorType).toBe('validation') + expect(result[0].code).toBe('INVALID_PARENT') + } + + // Verify NO nodes were created in the database (atomic rollback) + const allNodes = await nodesRepo.find({ where: { nodeMapId: map.id } }) + expect(allNodes.length).toBe(0) + }) + + it('successfully adds all nodes when all pass validation (atomic success)', async () => { + const map = await mapsRepo.save({}) + + // Create a valid root node + const rootNode = nodesRepo.create({ + id: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa', + nodeMapId: map.id, + coordinatesX: 1, + coordinatesY: 1, + root: true, + detached: false, + }) + + // Create a valid detached node + const detachedNode = nodesRepo.create({ + id: 'cccccccc-cccc-4ccc-8ccc-cccccccccccc', + nodeMapId: map.id, + coordinatesX: 3, + coordinatesY: 3, + root: false, + detached: true, + }) + + // Add root node first + const rootResult = await mapsService.addNodes(map.id, [rootNode]) + expect(rootResult.length).toBe(1) + expect('id' in rootResult[0]).toBe(true) + + // Add detached node + const detachedResult = await mapsService.addNodes(map.id, [detachedNode]) + expect(Array.isArray(detachedResult)).toBe(true) + expect(detachedResult.length).toBe(1) + expect('id' in detachedResult[0]).toBe(true) + + // Create a child node with reference to rootNode (after root is saved) + const childNode = nodesRepo.create({ + id: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb', + nodeMapId: map.id, + coordinatesX: 2, + coordinatesY: 2, + root: false, + detached: false, + nodeParentId: rootNode.id, + }) + + // Add child node (has parent reference to rootNode) + const childResult = await mapsService.addNodes(map.id, [childNode]) + expect(Array.isArray(childResult)).toBe(true) + expect(childResult.length).toBe(1) + expect('id' in childResult[0]).toBe(true) + + // Verify all nodes exist in database + const allNodes = await nodesRepo.find({ where: { nodeMapId: map.id } }) + expect(allNodes.length).toBe(3) + }) + }) + + describe('updateNode with ValidationErrorResponse', () => { + it('returns ValidationErrorResponse for invalid parent on update', async () => { + const map = await mapsRepo.save({}) + + const node = await nodesRepo.save({ + id: '78a2ae85-1815-46da-a2bc-a41de6bdd5cc', + nodeMapId: map.id, + coordinatesX: 3, + coordinatesY: 1, + root: true, + }) + + const clientNode = mapMmpNodeToClient(node) + // Set invalid parent (non-existent UUID) + clientNode.parent = '99999999-9999-9999-9999-999999999999' + clientNode.isRoot = false + + const result = await mapsService.updateNode(map.id, clientNode) + + // Should return ValidationErrorResponse + expect(result).toBeDefined() + if (result && 'errorType' in result) { + expect(result.success).toBe(false) + expect(result.errorType).toBe('validation') + // updateNode returns CONSTRAINT_VIOLATION for invalid parent + expect(result.code).toBe('CONSTRAINT_VIOLATION') + } + }) + }) + + describe('getMapsOfUser', () => { + it('returns [] if no userId is provided', async () => { + const result = await mapsService.getMapsOfUser('') + expect(result).toEqual([]) + }) + + it('returns only maps belonging to the given userId', async () => { + const user1 = 'user1' + const user2 = 'user2' + + const map1 = await mapsRepo.save({ ownerExternalId: user1 }) + const map2 = await mapsRepo.save({ ownerExternalId: user1 }) + await mapsRepo.save({ ownerExternalId: user2 }) + + const maps = await mapsService.getMapsOfUser(user1) + + expect(maps).toHaveLength(2) + expect(maps.map((m) => m.uuid)).toEqual( + expect.arrayContaining([map1.id, map2.id]) + ) }) }) }) diff --git a/teammapper-backend/src/map/services/maps.service.ts b/teammapper-backend/src/map/services/maps.service.ts index 03b64705a..6f3fb5a6e 100644 --- a/teammapper-backend/src/map/services/maps.service.ts +++ b/teammapper-backend/src/map/services/maps.service.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from '@nestjs/common' import { InjectRepository } from '@nestjs/typeorm' -import { Repository, QueryFailedError } from 'typeorm' +import { Repository, QueryFailedError, QueryRunner, In } from 'typeorm' import { MmpMap } from '../entities/mmpMap.entity' import { MmpNode } from '../entities/mmpNode.entity' import { @@ -10,6 +10,8 @@ import { IMmpClientNodeBasics, IMmpClientMapDiff, IMmpClientSnapshotChanges, + IMmpClientMapInfo, + ValidationErrorResponse, } from '../types' import { mapClientBasicNodeToMmpRootNode, @@ -29,6 +31,11 @@ import MalformedUUIDError from './uuid.error' export class MapsService { private readonly logger = new Logger(MapsService.name) + // PostgreSQL error codes for constraint violations + private static readonly PG_FOREIGN_KEY_VIOLATION = '23503' + private static readonly PG_UNIQUE_VIOLATION = '23505' + private static readonly PG_CHECK_VIOLATION = '23514' + constructor( @InjectRepository(MmpNode) private nodesRepository: Repository, @@ -36,6 +43,12 @@ export class MapsService { private mapsRepository: Repository ) {} + /** + * Checks if an error is a database constraint violation + * Detects PostgreSQL constraint errors: foreign key violations, unique violations, and check violations + * @param error The error to classify + * @returns true if the error is a constraint violation, false otherwise + */ private isConstraintError(error: unknown): boolean { if (!(error instanceof QueryFailedError)) { return false @@ -44,10 +57,72 @@ export class MapsService { // Check for foreign key constraint violations (PostgreSQL error codes) const pgError = error.driverError as { code?: string } return ( - pgError?.code === '23503' || // foreign_key_violation - pgError?.code === '23505' || // unique_violation - pgError?.code === '23514' // check_violation + pgError?.code === MapsService.PG_FOREIGN_KEY_VIOLATION || + pgError?.code === MapsService.PG_UNIQUE_VIOLATION || + pgError?.code === MapsService.PG_CHECK_VIOLATION + ) + } + + /** + * Finds the root node for a given map + */ + private async findRootNode(mapId: string): Promise { + return await this.nodesRepository.findOne({ + where: { nodeMapId: mapId, root: true }, + }) + } + + async getMapsOfUser(userId: string): Promise { + if (!userId) return [] + const mapsOfUser = await this.mapsRepository.find({ + where: { ownerExternalId: userId }, + }) + + const mapsInfo: IMmpClientMapInfo[] = await Promise.all( + mapsOfUser.map(async (map: MmpMap) => { + return { + uuid: map.id, + adminId: map.adminId, + modificationSecret: map.modificationSecret, + ttl: await this.getDeletedAt(map, configService.deleteAfterDays()), + rootName: (await this.findRootNode(map.id))?.name || null, + createdAt: map.createdAt, + } + }) ) + + mapsInfo.sort((a, b) => (b.ttl?.getTime() ?? 0) - (a.ttl?.getTime() ?? 0)) + + return mapsInfo.slice(0, 20) + } + + /** + * Maps database constraint errors to structured validation responses + */ + async mapConstraintErrorToValidationResponse( + error: QueryFailedError, + _node: Partial, + _mapId: string + ): Promise { + const pgError = error.driverError as { code?: string; detail?: string } + + // Determine error code based on constraint type + let code: ValidationErrorResponse['code'] = 'CONSTRAINT_VIOLATION' + if (pgError?.code === MapsService.PG_FOREIGN_KEY_VIOLATION) { + code = 'INVALID_PARENT' + } else if (pgError?.code === MapsService.PG_UNIQUE_VIOLATION) { + code = 'DUPLICATE_NODE' + } + + return { + success: false, + errorType: 'validation', + code, + message: `VALIDATION_ERROR.${code}`, + context: { + detail: pgError?.detail, + }, + } } findMap(uuid: string): Promise { @@ -85,6 +160,12 @@ export class MapsService { } } + /** + * Validates that node parent constraints are satisfied + * Root and detached nodes cannot have parents - this is a business rule + * @param node The node to validate + * @returns true if constraints are valid, false if violated + */ private validateNodeParentConstraints(node: MmpNode): boolean { if (node.detached && node.nodeParentId) { this.logger.warn( @@ -103,7 +184,10 @@ export class MapsService { return true } - async addNode(mapId: string, node: MmpNode): Promise { + async addNode( + mapId: string, + node: MmpNode + ): Promise { if (!mapId || !node) { this.logger.warn( `addNode(): Required arguments mapId or node not supplied` @@ -111,7 +195,15 @@ export class MapsService { return } - if (!this.validateNodeParentConstraints(node)) return + // Check node parent constraints + if (!this.validateNodeParentConstraints(node)) { + // Return validation error + return await this.mapConstraintErrorToValidationResponse( + new QueryFailedError('', [], new Error('CONSTRAINT_VIOLATION')), + node, + mapId + ) + } const existingNode = await this.nodesRepository.findOne({ where: { id: node.id, nodeMapId: mapId }, @@ -126,16 +218,22 @@ export class MapsService { try { return await this.nodesRepository.save(newNode) } catch (error) { - // Log with appropriate detail based on error type - if (this.isConstraintError(error)) { + // Check if it's a constraint error we can handle + if (this.isConstraintError(error) && error instanceof QueryFailedError) { this.logger.warn( `addNode(): Constraint violation when adding node ${newNode.id} - likely invalid parent reference` ) - } else { - this.logger.error( - `${error instanceof Error ? error.constructor.name : 'Unknown'} addNode(): Failed to add node ${newNode.id}: ${error instanceof Error ? error.message : String(error)}` + return await this.mapConstraintErrorToValidationResponse( + error, + newNode, + mapId ) } + + // For other errors, log and throw + this.logger.error( + `${error instanceof Error ? error.constructor.name : 'Unknown'} addNode(): Failed to add node ${newNode.id}: ${error instanceof Error ? error.message : String(error)}` + ) throw error } } @@ -143,15 +241,23 @@ export class MapsService { async addNodesFromClient( mapId: string, clientNodes: IMmpClientNode[] - ): Promise { + ): Promise<(MmpNode | ValidationErrorResponse)[]> { const mmpNodes = clientNodes.map((x) => mapClientNodeToMmpNode(x, mapId)) return await this.addNodes(mapId, mmpNodes) } + /** + * Adds multiple nodes to a map in a single atomic transaction + * If any node fails validation or save, the entire operation is rolled back + * Relies on database FK constraints for referential integrity + * @param mapId The map ID to add nodes to + * @param nodes Array of nodes to add + * @returns Array of created nodes on success, or array with single ValidationErrorResponse on failure + */ async addNodes( mapId: string, nodes: Partial[] - ): Promise { + ): Promise<(MmpNode | ValidationErrorResponse)[]> { if (!mapId || nodes.length === 0) { this.logger.warn( `Required arguments mapId or nodes not supplied to addNodes()` @@ -159,33 +265,219 @@ export class MapsService { return [] } - const reducer = async ( - previousPromise: Promise, - node: MmpNode - ): Promise => { - const accCreatedNodes = await previousPromise - if (await this.validatesNodeParentForNode(mapId, node)) { - try { - const newNode = await this.addNode(mapId, node) - if (newNode) { - return accCreatedNodes.concat([newNode]) - } - } catch (error) { - this.logger.warn( - `Failed to add node ${node.id} to map ${mapId}: ${error}` - ) + const queryRunner = await this.createQueryRunner() + + try { + await queryRunner.startTransaction() + + const businessRuleValidation = await this.validateBusinessRules(nodes) + if (!businessRuleValidation.valid) { + await queryRunner.rollbackTransaction() + return [businessRuleValidation.error!] + } + + const nodesToCreate = await this.filterOutExistingNodes( + queryRunner, + mapId, + nodes as MmpNode[] + ) + + const createdNodes = await this.saveAllNodesInTransaction( + queryRunner, + mapId, + nodesToCreate + ) + + await queryRunner.commitTransaction() + return createdNodes + } catch (error) { + await this.rollbackTransactionSafely(queryRunner) + return await this.handleAddNodesError(error, nodes, mapId) + } finally { + await this.releaseQueryRunnerSafely(queryRunner) + } + } + + /** + * Creates a validation error response directly + */ + private buildValidationError( + code: ValidationErrorResponse['code'], + message: string + ): ValidationErrorResponse { + return { + success: false, + errorType: 'validation', + code, + message: `VALIDATION_ERROR.${message}`, + } + } + + /** + * Validates business rules that the database cannot enforce + * Does not check FK constraints - those are validated by the database + * @param nodes Array of nodes to validate + * @returns Validation result with error if invalid + */ + private async validateBusinessRules(nodes: Partial[]): Promise<{ + valid: boolean + error?: ValidationErrorResponse + }> { + for (const node of nodes) { + // Validate required properties exist + if (!this.hasRequiredNodeProperties(node)) { + return { + valid: false, + error: this.buildValidationError( + 'MISSING_REQUIRED_FIELD', + 'MISSING_REQUIRED_FIELD' + ), } + } + + const mmpNode = node as MmpNode - return accCreatedNodes + // Business rule: root and detached nodes cannot have parents + if (!this.validateNodeParentConstraints(mmpNode)) { + return { + valid: false, + error: this.buildValidationError( + 'CONSTRAINT_VIOLATION', + 'CONSTRAINT_VIOLATION' + ), + } + } + } + + return { valid: true } + } + + /** + * Checks if a node has the minimum required property (id) for database save + * Other required properties (root, detached, coordinatesX, coordinatesY, nodeMapId) are either: + * - Set by database defaults (@Column({ default: ... })) + * - Set explicitly before save (nodeMapId) + * - Validated by TypeORM's @IsDefined() decorators during entity creation + */ + private hasRequiredNodeProperties(node: Partial): boolean { + return !!node.id + } + + /** + * Safely rolls back a transaction with error handling + * Only attempts rollback if transaction is active + */ + private async rollbackTransactionSafely( + queryRunner: QueryRunner + ): Promise { + try { + if (queryRunner.isTransactionActive) { + await queryRunner.rollbackTransaction() + } + } catch (rollbackError) { + this.logger.error( + `Failed to rollback transaction: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}` + ) + } + } + + /** + * Safely releases a query runner with error handling + * Only attempts release if not already released + */ + private async releaseQueryRunnerSafely( + queryRunner: QueryRunner + ): Promise { + try { + if (!queryRunner.isReleased) { + await queryRunner.release() } + } catch (releaseError) { + this.logger.error( + `Failed to release query runner: ${releaseError instanceof Error ? releaseError.message : String(releaseError)}` + ) + } + } + /** + * Handles errors during addNodes operation + * Safely handles constraint violations and re-throws unexpected errors + */ + private async handleAddNodesError( + error: unknown, + nodes: Partial[], + mapId: string + ): Promise<(MmpNode | ValidationErrorResponse)[]> { + // Handle constraint errors from database + if (this.isConstraintError(error) && error instanceof QueryFailedError) { this.logger.warn( - `Parent with id ${node.nodeParentId} does not exist for node ${node.id} and map ${mapId}` + `addNodes(): Constraint violation when adding nodes to map ${mapId}` ) - return accCreatedNodes + // Use first node if available, otherwise use empty object as fallback + const nodeForError = (nodes[0] ?? {}) as MmpNode + return [ + await this.mapConstraintErrorToValidationResponse( + error, + nodeForError, + mapId + ), + ] } - return nodes.reduce(reducer, Promise.resolve(new Array())) + // Re-throw unexpected errors + this.logger.error( + `${error instanceof Error ? error.constructor.name : 'Unknown'} addNodes(): Failed to add nodes to map ${mapId}: ${error instanceof Error ? error.message : String(error)}` + ) + throw error + } + + /** + * Filters out nodes that already exist in the database using a single bulk query + * Optimized to prevent N+1 query problem + */ + private async filterOutExistingNodes( + queryRunner: QueryRunner, + mapId: string, + nodes: MmpNode[] + ): Promise { + if (nodes.length === 0) { + return [] + } + + const nodeIds = nodes.map((n) => n.id) + const existingNodes = await queryRunner.manager.find(MmpNode, { + where: { + id: In(nodeIds), + nodeMapId: mapId, + }, + select: ['id'], + }) + + const existingNodeIds = new Set(existingNodes.map((n) => n.id)) + return nodes.filter((node) => !existingNodeIds.has(node.id)) + } + + /** + * Saves all nodes within a transaction using bulk insert for performance + * All nodes saved in single database operation + */ + private async saveAllNodesInTransaction( + queryRunner: QueryRunner, + mapId: string, + nodes: MmpNode[] + ): Promise { + if (nodes.length === 0) { + return [] + } + + const newNodes = nodes.map((node) => + queryRunner.manager.create(MmpNode, { + ...node, + nodeMapId: mapId, + }) + ) + + return await queryRunner.manager.save(newNodes) } async findNodes(mapId: string): Promise { @@ -199,6 +491,14 @@ export class MapsService { async existsNode(mapId: string, parentId: string): Promise { if (!mapId || !parentId) return false + // Validate UUID format before querying to avoid database errors + if (!uuidValidate(parentId)) { + this.logger.warn( + `existsNode(): Invalid UUID format for parentId: ${parentId}` + ) + return false + } + return await this.nodesRepository.exist({ where: { id: parentId, nodeMapId: mapId }, }) @@ -247,7 +547,7 @@ export class MapsService { async updateNode( mapId: string, clientNode: IMmpClientNode - ): Promise { + ): Promise { const existingNode = await this.nodesRepository.findOne({ where: { nodeMapId: mapId, id: clientNode.id }, }) @@ -269,12 +569,29 @@ export class MapsService { ) if (!parentIsValid) { - return undefined + // Return validation error + return await this.mapConstraintErrorToValidationResponse( + new QueryFailedError('', [], new Error('INVALID_PARENT')), + { ...existingNode, ...updatedNodeData }, + mapId + ) } try { return await this.saveUpdatedNode(existingNode, updatedNodeData) } catch (error) { + // Check if it's a constraint error we can handle + if (this.isConstraintError(error) && error instanceof QueryFailedError) { + this.logger.warn( + `updateNode(): Constraint violation when updating node ${existingNode.id}` + ) + return await this.mapConstraintErrorToValidationResponse( + error, + { ...existingNode, ...updatedNodeData }, + mapId + ) + } + this.logger.error( `${error instanceof Error ? error.constructor.name : 'Unknown'} updateNode(): Failed to update node ${existingNode.id}: ${error instanceof Error ? error.message : String(error)}` ) @@ -316,159 +633,301 @@ export class MapsService { } } - async createEmptyMap(rootNode?: IMmpClientNodeBasics): Promise { - const newMap: MmpMap = this.mapsRepository.create() + async createEmptyMap( + rootNode?: IMmpClientNodeBasics, + userId?: string + ): Promise { + const newMap: MmpMap = this.mapsRepository.create({ + ownerExternalId: userId, + }) const savedNewMap: MmpMap = await this.mapsRepository.save(newMap) if (rootNode) { await this.createRootNodeForMap(rootNode, savedNewMap.id) } - return newMap + return savedNewMap } - // updates map nodes + /** + * Updates map by replacing all nodes in a transaction + * Ensures atomicity - either all changes succeed or none do + */ async updateMap(clientMap: IMmpClientMap): Promise { - // Use a transaction to ensure atomicity - either all changes succeed or none do + const queryRunner = await this.createQueryRunner() + + try { + await this.startMapUpdateTransaction(queryRunner) + await this.deleteExistingNodes(queryRunner, clientMap.uuid) + await this.addValidatedNodes(queryRunner, clientMap) + await this.commitMapTransaction(queryRunner) + return this.findMap(clientMap.uuid) + } catch (error) { + await this.rollbackMapTransaction(queryRunner, clientMap.uuid, error) + throw error + } finally { + await queryRunner.release() + } + } + + /** + * Creates and connects a query runner for transaction management + */ + private async createQueryRunner() { const queryRunner = this.nodesRepository.manager.connection.createQueryRunner() await queryRunner.connect() + return queryRunner + } + + /** + * Starts a database transaction for map updates + */ + private async startMapUpdateTransaction( + queryRunner: QueryRunner + ): Promise { await queryRunner.startTransaction() + } + + /** + * Deletes all existing nodes for a map + * Prevents multiple root nodes in the updated map + */ + private async deleteExistingNodes( + queryRunner: QueryRunner, + mapId: string + ): Promise { + await queryRunner.manager.delete(MmpNode, { nodeMapId: mapId }) + } + + /** + * Adds new nodes from client map with validation + * Validates parent relationships before adding each node + */ + private async addValidatedNodes( + queryRunner: QueryRunner, + clientMap: IMmpClientMap + ): Promise { + const mmpNodes = this.convertClientNodesToMmpNodes(clientMap) + await this.saveValidNodes(queryRunner, mmpNodes, clientMap.uuid) + } + + /** + * Converts client nodes to MmpNode format + */ + private convertClientNodesToMmpNodes( + clientMap: IMmpClientMap + ): Partial[] { + return clientMap.data.map((x) => mapClientNodeToMmpNode(x, clientMap.uuid)) + } + + /** + * Saves valid nodes sequentially to avoid race conditions + */ + private async saveValidNodes( + queryRunner: QueryRunner, + mmpNodes: Partial[], + mapId: string + ): Promise { + for (const node of mmpNodes) { + await this.saveNodeIfValid(queryRunner, node as MmpNode, mapId) + } + } + + /** + * Saves a single node if it passes validation + */ + private async saveNodeIfValid( + queryRunner: QueryRunner, + node: MmpNode, + mapId: string + ): Promise { + if (await this.validatesNodeParentForNode(mapId, node)) { + const newNode = queryRunner.manager.create(MmpNode, { + ...node, + nodeMapId: mapId, + }) + await queryRunner.manager.save(newNode) + } + } + + /** + * Commits the map update transaction + */ + private async commitMapTransaction(queryRunner: QueryRunner): Promise { + await queryRunner.commitTransaction() + } + + /** + * Rolls back transaction and logs error + */ + private async rollbackMapTransaction( + queryRunner: QueryRunner, + mapId: string, + error: unknown + ): Promise { + await queryRunner.rollbackTransaction() + this.logger.error( + `updateMap(): Failed to update map ${mapId}: ${error instanceof Error ? error.message : String(error)}` + ) + } + + /** + * Updates map by applying incremental changes (diff) in a single atomic transaction + * If any change (add/update/delete) fails, the entire operation is rolled back + * Ensures atomicity - either all changes succeed or none do + * @param mapId The map ID to update + * @param diff The diff containing added, updated, and deleted nodes + */ + async updateMapByDiff(mapId: string, diff: IMmpClientMapDiff): Promise { + const queryRunner = await this.createQueryRunner() try { - // Remove existing nodes, otherwise we will end up with multiple roots - await queryRunner.manager.delete(MmpNode, { nodeMapId: clientMap.uuid }) + await queryRunner.startTransaction() - // Add new nodes from given map - const mmpNodes = clientMap.data.map((x) => - mapClientNodeToMmpNode(x, clientMap.uuid) - ) + // Process deleted nodes first to avoid FK constraint issues + if (diff.deleted && Object.keys(diff.deleted).length > 0) { + await this.applyDeletedChangesInTransaction( + queryRunner, + mapId, + diff.deleted + ) + } - // Validate and add nodes sequentially to avoid race conditions - for (const node of mmpNodes) { - // Cast to MmpNode since mapClientNodeToMmpNode returns Partial - const fullNode = node as MmpNode - if (await this.validatesNodeParentForNode(clientMap.uuid, fullNode)) { - const newNode = queryRunner.manager.create(MmpNode, { - ...fullNode, - nodeMapId: clientMap.uuid, - }) - await queryRunner.manager.save(newNode) - } + // Process added nodes + if (diff.added && Object.keys(diff.added).length > 0) { + await this.applyAddedChangesInTransaction( + queryRunner, + mapId, + diff.added + ) } - // Commit transaction - await queryRunner.commitTransaction() + // Process updated nodes + if (diff.updated && Object.keys(diff.updated).length > 0) { + await this.applyUpdatedChangesInTransaction( + queryRunner, + mapId, + diff.updated + ) + } - // Reload map - return this.findMap(clientMap.uuid) + await queryRunner.commitTransaction() } catch (error) { - // Rollback transaction on error - await queryRunner.rollbackTransaction() + await this.rollbackTransactionSafely(queryRunner) this.logger.error( - `updateMap(): Failed to update map ${clientMap.uuid}: ${error instanceof Error ? error.message : String(error)}` + `updateMapByDiff(): Failed to apply changes to map ${mapId}: ${error instanceof Error ? error.message : String(error)}` ) throw error } finally { - // Release query runner - await queryRunner.release() + await this.releaseQueryRunnerSafely(queryRunner) } } - async updateMapByDiff(mapId: string, diff: IMmpClientMapDiff) { - type DiffCallback = (diff: IMmpClientSnapshotChanges) => Promise - type DiffKey = keyof IMmpClientMapDiff + /** + * Applies deleted changes within a transaction + */ + private async applyDeletedChangesInTransaction( + queryRunner: QueryRunner, + mapId: string, + deletedNodes: IMmpClientSnapshotChanges + ): Promise { + const nodeIds = Object.keys(deletedNodes) - const diffAddedCallback: DiffCallback = async ( - diff: IMmpClientSnapshotChanges - ) => { - const nodes = Object.values(diff) - await this.addNodesFromClient(mapId, nodes as IMmpClientNode[]) + // Delete all nodes in a single query + if (nodeIds.length > 0) { + await queryRunner.manager.delete(MmpNode, { + id: In(nodeIds), + nodeMapId: mapId, + }) } + } - const updateSingleNodeFromDiff = async ( - key: string, - clientNode: Partial | undefined - ): Promise => { - if (!clientNode) return - - const serverNode = await this.nodesRepository.findOne({ - where: { nodeMapId: mapId, id: key }, - }) + /** + * Applies added changes within a transaction + */ + private async applyAddedChangesInTransaction( + queryRunner: QueryRunner, + mapId: string, + addedNodes: IMmpClientSnapshotChanges + ): Promise { + const clientNodes = Object.values(addedNodes) as IMmpClientNode[] + const mmpNodes = clientNodes.map((x) => mapClientNodeToMmpNode(x, mapId)) - if (!serverNode) return + // Validate business rules for all nodes + const businessRuleValidation = await this.validateBusinessRules(mmpNodes) + if (!businessRuleValidation.valid) { + throw new Error( + `Business rule validation failed: ${businessRuleValidation.error?.message}` + ) + } - const mergedNode = mergeClientNodeIntoMmpNode(clientNode, serverNode) + // Filter out existing nodes and save new ones + const nodesToCreate = await this.filterOutExistingNodes( + queryRunner, + mapId, + mmpNodes as MmpNode[] + ) - const parentIsValid = await this.validateNodeParentExists( - mapId, - key, - mergedNode, - 'diffUpdatedCallback()' - ) + if (nodesToCreate.length > 0) { + await this.saveAllNodesInTransaction(queryRunner, mapId, nodesToCreate) + } + } - if (!parentIsValid) return + /** + * Applies updated changes within a transaction + * + * Error Handling Strategy: + * - Missing nodes (not found in database) are skipped with a warning (lenient) + * Rationale: Node may have been deleted by concurrent operation, acceptable for optimistic updates + * - Invalid parent references throw errors and roll back transaction (strict) + * Rationale: Invalid parents indicate data integrity violation or client state inconsistency + * that should fail the entire atomic operation + * + * This differential handling balances robustness (handling race conditions gracefully) + * with data integrity (preventing orphaned or corrupted node relationships) + */ + private async applyUpdatedChangesInTransaction( + queryRunner: QueryRunner, + mapId: string, + updatedNodes: IMmpClientSnapshotChanges + ): Promise { + // Process updates sequentially to maintain parent-child relationship order + for (const [nodeId, clientNodeData] of Object.entries(updatedNodes)) { + if (!clientNodeData) continue - Object.assign(serverNode, mergedNode) + const serverNode = await queryRunner.manager.findOne(MmpNode, { + where: { nodeMapId: mapId, id: nodeId }, + }) - try { - await this.nodesRepository.save(serverNode) - } catch (error) { - this.logger.error( - `${error instanceof Error ? error.constructor.name : 'Unknown'} diffUpdatedCallback(): Failed to update node ${serverNode.id}: ${error instanceof Error ? error.message : String(error)}` + if (!serverNode) { + this.logger.warn( + `updateMapByDiff(): Node ${nodeId} not found for update, skipping` ) - // Don't reject - just log and continue with other updates + continue } - } - const diffUpdatedCallback: DiffCallback = async ( - diff: IMmpClientSnapshotChanges - ) => { - // Process updates sequentially to avoid race conditions with parent-child relationships - for (const key of Object.keys(diff)) { - await updateSingleNodeFromDiff(key, diff[key]) - } - } + const mergedNode = mergeClientNodeIntoMmpNode(clientNodeData, serverNode) - const diffDeletedCallback: DiffCallback = async ( - diff: IMmpClientSnapshotChanges - ) => { - await Promise.all( - Object.keys(diff).map(async (key) => { - const existingNode = await this.nodesRepository.findOneBy({ - id: key, + // Validate parent exists if specified + if (shouldValidateParent(mergedNode)) { + const parentExists = await queryRunner.manager.exists(MmpNode, { + where: { + id: mergedNode.nodeParentId!, nodeMapId: mapId, - }) - - if (!existingNode) { - return - } - - return this.nodesRepository.remove(existingNode) + }, }) - ) - } - - const callbacks: Record = { - added: diffAddedCallback, - updated: diffUpdatedCallback, - deleted: diffDeletedCallback, - } - const diffKeys: DiffKey[] = ['added', 'updated', 'deleted'] - - for (const key of diffKeys) { - const changes = diff[key] - if (changes && Object.keys(changes).length > 0) { - try { - await callbacks[key](changes) - } catch (error) { - this.logger.error( - `Failed to apply ${key} changes in updateMapByDiff: ${error instanceof Error ? error.message : String(error)}` + if (!parentExists) { + throw new Error( + `Invalid parent reference: Parent node ${mergedNode.nodeParentId} does not exist for node ${nodeId}` ) - // Continue processing other changes even if one fails } } + + // Apply changes and save + Object.assign(serverNode, mergedNode, { lastModified: new Date() }) + await queryRunner.manager.save(serverNode) } } diff --git a/teammapper-backend/src/map/types.ts b/teammapper-backend/src/map/types.ts index 94fda2ea4..6b6cde78b 100644 --- a/teammapper-backend/src/map/types.ts +++ b/teammapper-backend/src/map/types.ts @@ -32,6 +32,15 @@ export interface IMmpClientMap { createdAt: Date | null } +export interface IMmpClientMapInfo { + uuid: string + adminId: string | null + modificationSecret: string | null + ttl: Date | undefined + createdAt: Date | null + rootName: string | null +} + export interface IMmpClientPrivateMap { map: IMmpClientMap adminId: string | null @@ -127,3 +136,86 @@ export interface IMermaidCreateRequest { mindmapDescription: string language: string } + +// Operation tracking types for optimistic updates +export type OperationType = 'create' | 'update' | 'delete' | 'updateProperty' + +export type OperationStatus = 'pending' | 'confirmed' | 'rejected' | 'timedout' + +// Error response types for structured error handling +export interface BaseErrorResponse { + /** Success indicator (always false for errors) */ + success: false + + /** Type of error for classification */ + errorType: 'validation' | 'critical' + + /** Machine-readable error code */ + code: string + + /** i18n key for user-facing message */ + message: string + + /** Optional additional context (not shown to user) */ + context?: Record +} + +export interface ValidationErrorResponse extends BaseErrorResponse { + errorType: 'validation' + + /** Specific validation error codes */ + code: + | 'INVALID_PARENT' + | 'CONSTRAINT_VIOLATION' + | 'MISSING_REQUIRED_FIELD' + | 'CIRCULAR_REFERENCE' + | 'DUPLICATE_NODE' + + /** Full map state for client synchronization after errors */ + fullMapState?: IMmpClientMap +} + +export interface CriticalErrorResponse extends BaseErrorResponse { + errorType: 'critical' + + /** Specific critical error codes */ + code: + | 'SERVER_ERROR' + | 'NETWORK_TIMEOUT' + | 'AUTH_FAILED' + | 'MALFORMED_REQUEST' + | 'RATE_LIMIT_EXCEEDED' + + /** Optional retry-after value for rate limiting */ + retryAfter?: number + + /** Full map state for client synchronization after errors */ + fullMapState?: IMmpClientMap +} + +export interface SuccessResponse { + /** Success indicator */ + success: true + + /** Result data from the operation */ + data: T + + /** Optional metadata */ + meta?: { + timestamp: number + operationId?: string + } +} + +export interface Request { + cookies: { + access_token?: string + person_id?: string + } + pid: string | undefined +} + +export type OperationResponse = + | SuccessResponse + | ValidationErrorResponse + | CriticalErrorResponse diff --git a/teammapper-backend/src/settings/settings.controller.ts b/teammapper-backend/src/settings/settings.controller.ts new file mode 100644 index 000000000..8b3409434 --- /dev/null +++ b/teammapper-backend/src/settings/settings.controller.ts @@ -0,0 +1,12 @@ +import { Controller, Get } from '@nestjs/common' +import { SettingsService } from './settings.service' + +@Controller('api/settings') +export class SettingsController { + constructor(private readonly settingsService: SettingsService) {} + + @Get() + getSettings() { + return this.settingsService.getSettings() + } +} diff --git a/teammapper-backend/src/settings/settings.module.ts b/teammapper-backend/src/settings/settings.module.ts new file mode 100644 index 000000000..0a585dbdc --- /dev/null +++ b/teammapper-backend/src/settings/settings.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common' +import { SettingsController } from './settings.controller' +import { SettingsService } from './settings.service' + +@Module({ + controllers: [SettingsController], + providers: [SettingsService], +}) +export class SettingsModule {} diff --git a/teammapper-backend/src/settings/settings.service.ts b/teammapper-backend/src/settings/settings.service.ts new file mode 100644 index 000000000..8d04d36de --- /dev/null +++ b/teammapper-backend/src/settings/settings.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@nestjs/common' +import * as fs from 'fs' +import * as path from 'path' +import deepmerge from 'deepmerge' + +@Injectable() +export class SettingsService { + private readonly mode = process.env.MODE == 'prod' ? 'prod' : 'dev' + private readonly defaultSettingsPath = path.join( + __dirname, + '../..', + `config/settings.${this.mode}.json` + ) + + private readonly overrideSettingsPath = path.join( + __dirname, + '../..', + 'config/settings.override.json' + ) + + getSettings() { + const defaultFileData = fs.readFileSync(this.defaultSettingsPath, 'utf-8') + const defaultSettings = JSON.parse(defaultFileData) + + let overrideSettings = {} + + if ( + fs.existsSync(this.overrideSettingsPath) && + fs.statSync(this.overrideSettingsPath).size > 0 + ) { + const overrideFileData = fs.readFileSync( + this.overrideSettingsPath, + 'utf-8' + ) + overrideSettings = JSON.parse(overrideFileData) + } + + return deepmerge(defaultSettings, overrideSettings) + } +} diff --git a/teammapper-backend/test/app.e2e-spec.ts b/teammapper-backend/test/app.e2e-spec.ts index aa224a09e..3ec06db46 100644 --- a/teammapper-backend/test/app.e2e-spec.ts +++ b/teammapper-backend/test/app.e2e-spec.ts @@ -7,13 +7,13 @@ import { getRepositoryToken, TypeOrmModule } from '@nestjs/typeorm' import { Repository } from 'typeorm' import { ConfigModule } from '@nestjs/config' import { io, Socket } from 'socket.io-client' -import { IMmpClientMap } from 'src/map/types' +import { IMmpClientMap, OperationResponse, IMmpClientNode } from 'src/map/types' import { createTestConfiguration, destroyWorkerDatabase } from './db' import AppModule from '../src/app.module' describe('AppController (e2e)', () => { let app: INestApplication - let server: any + let server: ReturnType let nodesRepo: Repository let mapRepo: Repository @@ -132,13 +132,9 @@ describe('AppController (e2e)', () => { ) }) - it('notifies a user about a new node', (done) => { - socket.on('nodesAdded', (result: any) => { - expect(result.nodes[0].name).toEqual('test') - done() - }) - + it('responds with success when adding a new node', (done) => { const mapId = crypto.randomUUID() + const nodeId = crypto.randomUUID() mapRepo .save({ @@ -147,36 +143,42 @@ describe('AppController (e2e)', () => { }) .then((map) => { socket.emit('join', { mapId: map.id, color: '#FFFFFF' }, () => { - socket.emit('addNodes', { - mapId: map.id, - modificationSecret: map.modificationSecret, - nodes: [ - { - name: 'test', - coordinates: { x: 1, y: 2 }, - font: {}, - colors: {}, - link: {}, - isRoot: true, - detached: false, - }, - ], - }) + socket.emit( + 'addNodes', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + nodes: [ + { + id: nodeId, + name: 'test', + coordinates: { x: 1, y: 2 }, + font: {}, + colors: {}, + link: {}, + isRoot: true, + detached: false, + }, + ], + }, + (result: OperationResponse) => { + // Now we check the acknowledgment response + expect(result.success).toBe(true) + if ('data' in result) { + expect(result.data).toBeDefined() + expect(result.data[0].name).toEqual('test') + } + done() + } + ) }) }) }) - it('notifies a user about a node update', (done) => { + it('responds with success when updating a node', (done) => { const mapId = crypto.randomUUID() const nodeId = crypto.randomUUID() - socket.on('nodeUpdated', (result: any) => { - expect(result.property).toEqual('nodeName') - expect(result.node.id).toEqual(nodeId) - expect(result.node.coordinates.x).toEqual(3) - done() - }) - mapRepo .save({ id: mapId, @@ -194,21 +196,34 @@ describe('AppController (e2e)', () => { }) .then((map) => { socket.emit('join', { mapId: map.id, color: '#FFFFFF' }, () => { - socket.emit('updateNode', { - mapId: map.id, - modificationSecret: map.modificationSecret, - updatedProperty: 'nodeName', - node: { - id: nodeId, - name: 'test', - coordinates: { x: 3, y: 4 }, - font: {}, - colors: {}, - link: {}, - detached: false, - root: true, + socket.emit( + 'updateNode', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + updatedProperty: 'nodeName', + node: { + id: nodeId, + name: 'test', + coordinates: { x: 3, y: 4 }, + font: {}, + colors: {}, + link: {}, + detached: false, + root: true, + }, }, - }) + (result: OperationResponse) => { + // Now we check the acknowledgment response + expect(result.success).toBe(true) + if ('data' in result) { + expect(result.data).toBeDefined() + expect(result.data.id).toEqual(nodeId) + expect(result.data.coordinates.x).toEqual(3) + } + done() + } + ) }) }) }) diff --git a/teammapper-backend/test/jest-e2e.json b/teammapper-backend/test/jest-e2e.json index de3806ae7..48fb5a49d 100644 --- a/teammapper-backend/test/jest-e2e.json +++ b/teammapper-backend/test/jest-e2e.json @@ -6,6 +6,5 @@ "transform": { "^.+\\.(t|j)s$": "ts-jest" }, - "modulePaths": [""], - "testRunner": "jest-jasmine2" + "modulePaths": [""] } diff --git a/teammapper-backend/test/map-operations-error.e2e-spec.ts b/teammapper-backend/test/map-operations-error.e2e-spec.ts new file mode 100644 index 000000000..5366cf7ba --- /dev/null +++ b/teammapper-backend/test/map-operations-error.e2e-spec.ts @@ -0,0 +1,278 @@ +import { Test, TestingModule } from '@nestjs/testing' +import { INestApplication } from '@nestjs/common' +import { MmpMap } from '../src/map/entities/mmpMap.entity' +import { MmpNode } from '../src/map/entities/mmpNode.entity' +import { getRepositoryToken, TypeOrmModule } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { ConfigModule } from '@nestjs/config' +import { io, Socket } from 'socket.io-client' +import { + OperationResponse, + ValidationErrorResponse, + IMmpClientNode, +} from '../src/map/types' +import { createTestConfiguration, destroyWorkerDatabase } from './db' +import AppModule from '../src/app.module' + +// Using IMmpClientNode as the return type for node operations +type ExportNodeProperties = IMmpClientNode + +const crypto = require('crypto') // eslint-disable-line @typescript-eslint/no-require-imports + +describe('Map Operations Error Handling (e2e)', () => { + let app: INestApplication + let nodesRepo: Repository + let mapRepo: Repository + + beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [ + ConfigModule, + TypeOrmModule.forRoot( + await createTestConfiguration(process.env.JEST_WORKER_ID || '') + ), + AppModule, + ], + }).compile() + + nodesRepo = moduleFixture.get>( + getRepositoryToken(MmpNode) + ) + mapRepo = moduleFixture.get>(getRepositoryToken(MmpMap)) + app = moduleFixture.createNestApplication() + await app.init() + await app.listen(3002) + }) + + afterAll(async () => { + await destroyWorkerDatabase( + mapRepo.manager.connection, + process.env.JEST_WORKER_ID || '' + ) + await app.close() + }) + + describe('addNodes - ValidationErrorResponse structure', () => { + let socket: Socket + + beforeEach(() => { + socket = io('http://localhost:3002') + }) + + afterEach(() => { + socket.close() + }) + + it('returns ValidationErrorResponse for invalid parent', (done) => { + const mapId = crypto.randomUUID() + const rootNodeId = crypto.randomUUID() + const modificationSecret = crypto.randomUUID() + + mapRepo + .save({ + id: mapId, + modificationSecret: modificationSecret, + }) + .then(() => { + return nodesRepo.save({ + id: rootNodeId, + nodeMapId: mapId, + root: true, + detached: false, + coordinatesX: 0, + coordinatesY: 0, + }) + }) + .then(() => { + socket.emit('join', { mapId, color: '#FFFFFF' }, () => { + socket.emit( + 'addNodes', + { + mapId: mapId, + modificationSecret: modificationSecret, + nodes: [ + { + id: crypto.randomUUID(), + name: 'Invalid Node', + coordinates: { x: 1, y: 2 }, + parent: '99999999-9999-9999-9999-999999999999', + isRoot: false, + detached: false, + }, + ], + }, + (response: OperationResponse) => { + // Socket.io acknowledgment contains ValidationErrorResponse structure + if (response.success === false) { + const validationError = response as ValidationErrorResponse + expect(validationError.errorType).toBe('validation') + expect(validationError.code).toBeDefined() + expect(validationError.message).toBeDefined() + done() + } else { + done.fail('Expected validation error response') + } + } + ) + }) + }) + }) + + it('returns SuccessResponse structure on successful operation', (done) => { + const mapId = crypto.randomUUID() + const modificationSecret = crypto.randomUUID() + + mapRepo + .save({ + id: mapId, + modificationSecret: modificationSecret, + }) + .then((map) => { + socket.emit('join', { mapId: map.id, color: '#FFFFFF' }, () => { + socket.emit( + 'addNodes', + { + mapId: map.id, + modificationSecret: map.modificationSecret, + nodes: [ + { + id: crypto.randomUUID(), + name: 'Valid Node', + coordinates: { x: 1, y: 2 }, + isRoot: true, + detached: false, + }, + ], + }, + (response: OperationResponse) => { + // Successful operations return SuccessResponse structure + expect(response.success).toBe(true) + if (response.success) { + expect(response.data).toBeDefined() + expect(Array.isArray(response.data)).toBe(true) + } + done() + } + ) + }) + }) + }) + }) + + describe('updateNode - ValidationErrorResponse structure', () => { + let socket: Socket + + beforeEach(() => { + socket = io('http://localhost:3002') + }) + + afterEach(() => { + socket.close() + }) + + it('returns ValidationErrorResponse for invalid parent update', (done) => { + const mapId = crypto.randomUUID() + const nodeId = crypto.randomUUID() + const modificationSecret = crypto.randomUUID() + + mapRepo + .save({ + id: mapId, + modificationSecret: modificationSecret, + }) + .then(() => { + return nodesRepo.save({ + id: nodeId, + nodeMapId: mapId, + root: true, + detached: false, + coordinatesX: 1, + coordinatesY: 2, + }) + }) + .then(() => { + socket.emit('join', { mapId, color: '#FFFFFF' }, () => { + socket.emit( + 'updateNode', + { + mapId: mapId, + modificationSecret: modificationSecret, + updatedProperty: 'parent', + node: { + id: nodeId, + name: 'Updated Node', + coordinates: { x: 3, y: 4 }, + parent: '99999999-9999-9999-9999-999999999999', + isRoot: false, + detached: false, + }, + }, + (response: OperationResponse) => { + // Socket.io acknowledgment contains ValidationErrorResponse structure + if (response.success === false) { + const validationError = response as ValidationErrorResponse + expect(validationError.errorType).toBe('validation') + // updateNode returns CONSTRAINT_VIOLATION for invalid parent + expect(validationError.code).toBe('CONSTRAINT_VIOLATION') + done() + } else { + done.fail('Expected validation error response') + } + } + ) + }) + }) + }) + + it('returns SuccessResponse structure on successful update', (done) => { + const mapId = crypto.randomUUID() + const nodeId = crypto.randomUUID() + const modificationSecret = crypto.randomUUID() + + mapRepo + .save({ + id: mapId, + modificationSecret: modificationSecret, + }) + .then(() => { + return nodesRepo.save({ + id: nodeId, + nodeMapId: mapId, + root: true, + detached: false, + coordinatesX: 1, + coordinatesY: 2, + }) + }) + .then(() => { + socket.emit('join', { mapId, color: '#FFFFFF' }, () => { + socket.emit( + 'updateNode', + { + mapId: mapId, + modificationSecret: modificationSecret, + updatedProperty: 'name', + node: { + id: nodeId, + name: 'Successfully Updated', + coordinates: { x: 1, y: 2 }, + root: true, + detached: false, + }, + }, + (response: OperationResponse) => { + // Successful operations return SuccessResponse structure + expect(response.success).toBe(true) + if (response.success) { + expect(response.data).toBeDefined() + expect(response.data.id).toBe(nodeId) + expect(response.data.name).toBe('Successfully Updated') + } + done() + } + ) + }) + }) + }) + }) +}) diff --git a/teammapper-frontend/CLAUDE.md b/teammapper-frontend/CLAUDE.md index 980ee4ae1..41b8140a6 100644 --- a/teammapper-frontend/CLAUDE.md +++ b/teammapper-frontend/CLAUDE.md @@ -9,9 +9,10 @@ TeamMapper is a collaborative web-based mind mapping application built with Angu ## Development best pracices - **Reusing existing code**: Please check before adding new types and functions if code is already available that solves the same purpose and that can be reused -- **Be specific with types**: Request explicit interfaces, enums, and type annotations rather than `any` +- **Be specific with types**: Request explicit interfaces, enums, and type annotations rather than `any`. ``any`is forbidden. Do only use typescript line ignores when absolutely necessary. - **Include error handling**: Ask for proper try/catch blocks and error types - **Request documentation**: Ask for comments on functions and complex types, but no need for full JSDoc +- **Method length**: Methods should usually have a maximum of 10 lines. If it exceeds this maximum, please use the extract method pattern. All methods should be well described and easy to read. ## Development Workflow @@ -27,6 +28,8 @@ pnpm run prettier --write src ## Development Commands +Important: You are in a docker container (app). Do not try to execute any docker commands as they will not work. Try to connect to other containers but do not execute docker commands directly, it wont work. + ```bash # Install dependencies pnpm install diff --git a/teammapper-frontend/angular.json b/teammapper-frontend/angular.json index 1a8cd2fc6..724d339c6 100644 --- a/teammapper-frontend/angular.json +++ b/teammapper-frontend/angular.json @@ -76,14 +76,15 @@ "builder": "@angular-devkit/build-angular:dev-server", "options": { "proxyConfig": "src/proxy.conf.json", - "buildTarget": "teammapper:build" + "buildTarget": "teammapper:build", + "allowedHosts": ["localhost", "127.0.0.1", "app", ".app", "host.docker.internal"] }, "configurations": { "production": { "buildTarget": "teammapper:build:production" }, "development": { - "buildTarget": "teammapper:build:development", + "buildTarget": "teammapper:build:development" } }, "defaultConfiguration": "development" diff --git a/teammapper-frontend/e2e/node-editing.spec.ts b/teammapper-frontend/e2e/node-editing.spec.ts index 232db2953..d883876f9 100644 --- a/teammapper-frontend/e2e/node-editing.spec.ts +++ b/teammapper-frontend/e2e/node-editing.spec.ts @@ -67,7 +67,7 @@ test('adds a node and drags it - screenshot test', async ({ page }) => { // Take a screenshot of the map after dragging await expect(page.locator('.map')).toHaveScreenshot('node-before-drag.png', { timeout: 500, - maxDiffPixels: 150, + maxDiffPixels: 150, animations: 'disabled', mask: [page.locator('.mat-toolbar')], // Mask the toolbar as it may vary }); @@ -94,7 +94,7 @@ test('adds a node and drags it - screenshot test', async ({ page }) => { // Take a screenshot of the map after dragging await expect(page.locator('.map')).toHaveScreenshot('node-after-drag.png', { timeout: 500, - maxDiffPixels: 150, + maxDiffPixels: 150, animations: 'disabled', mask: [page.locator('.mat-toolbar')], // Mask the toolbar as it may vary }); diff --git a/teammapper-frontend/package.json b/teammapper-frontend/package.json index 38d5fec94..49b169fc5 100644 --- a/teammapper-frontend/package.json +++ b/teammapper-frontend/package.json @@ -40,38 +40,38 @@ "format": "npx prettier . --write" }, "dependencies": { - "@angular-devkit/build-angular": "20.3.2", - "@angular/animations": "20.3.1", - "@angular/cdk": "20.0.2", - "@angular/cli": "20.3.2", - "@angular/common": "20.3.1", - "@angular/compiler": "20.3.1", - "@angular/compiler-cli": "20.3.1", - "@angular/core": "20.3.1", - "@angular/forms": "20.3.1", - "@angular/material": "20.0.2", - "@angular/platform-browser": "20.3.1", - "@angular/platform-browser-dynamic": "20.3.1", - "@angular/router": "20.3.1", + "@angular-devkit/build-angular": "20.3.7", + "@angular/animations": "20.3.7", + "@angular/cdk": "20.2.10", + "@angular/cli": "20.3.7", + "@angular/common": "20.3.7", + "@angular/compiler": "20.3.7", + "@angular/compiler-cli": "20.3.7", + "@angular/core": "20.3.7", + "@angular/forms": "20.3.7", + "@angular/material": "20.2.10", + "@angular/platform-browser": "20.3.7", + "@angular/platform-browser-dynamic": "20.3.7", + "@angular/router": "20.3.7", "@fortawesome/angular-fontawesome": "^2.0.1", "@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/free-brands-svg-icons": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", - "@material-design-icons/font": "^0.14.13", - "@ngx-translate/core": "^16.0.3", + "@material-design-icons/font": "^0.14.15", + "@ngx-translate/core": "^16.0.4", "@ngx-translate/http-loader": "^16.0.1", + "@teammapper/mermaid-mindmap-parser": "workspace:^", "@types/uuid": "^10.0.0", - "ai": "^5.0.40", + "ai": "^5.0.80", "angular2-hotkeys": "^16.0.1", - "d3": "7.6.1", + "d3": "7.9.0", "deep-object-diff": "^1.1.9", - "dompurify": "3.2.4", - "jspdf": "^3.0.2", + "dompurify": "3.3.0", + "jspdf": "^3.0.3", "localforage": "1.10.0", "ngx-color-picker": "^17.0.0", - "ngx-toastr": "^19.0.0", - "@teammapper/mermaid-mindmap-parser": "workspace:^0.0.1", - "qr-code-styling": "1.9.1", + "ngx-toastr": "^19.1.0", + "qr-code-styling": "1.9.2", "rxjs": "~7.8.2", "socket.io-client": "~4.8.1", "tslib": "^2.8.1", @@ -80,44 +80,43 @@ }, "devDependencies": { "@angular-builders/jest": "^20.0.0", - "@angular-devkit/architect": "0.2003.2", - "@angular-devkit/core": "20.3.2", - "@angular-devkit/schematics": "20.3.2", - "@angular-eslint/builder": "20.2.0", - "@angular-eslint/eslint-plugin": "20.2.0", - "@angular-eslint/eslint-plugin-template": "20.2.0", - "@angular-eslint/schematics": "20.2.0", - "@angular-eslint/template-parser": "20.2.0", - "@angular/language-service": "20.3.1", - "@compodoc/compodoc": "^1.1.26", - "@eslint/js": "^9.34.0", - "@playwright/test": "^1.55.0", - "@schematics/angular": "^19.2.12", - "@types/d3": "7.1.0", - "@types/jasmine": "~5.1.4", - "@types/jest": "29.5.14", + "@angular-devkit/architect": "0.2003.8", + "@angular-devkit/core": "20.3.8", + "@angular-devkit/schematics": "20.3.8", + "@angular-eslint/builder": "20.5.0", + "@angular-eslint/eslint-plugin": "20.5.0", + "@angular-eslint/eslint-plugin-template": "20.5.0", + "@angular-eslint/schematics": "20.5.0", + "@angular-eslint/template-parser": "20.5.0", + "@angular/language-service": "20.3.9", + "@compodoc/compodoc": "^1.1.32", + "@eslint/js": "^9.39.0", + "@playwright/test": "^1.57.0", + "@schematics/angular": "^20.3.8", + "@types/d3": "7.4.3", + "@types/jest": "30.0.0", "@types/mousetrap": "1.6.15", - "@types/node": "^22.15.19", - "@typescript-eslint/eslint-plugin": "^8.41.0", - "@typescript-eslint/parser": "^8.41.0", - "angular-eslint": "^20.2.0", - "eslint": "^9.34.0", + "@types/node": "^24.9.2", + "@typescript-eslint/eslint-plugin": "^8.46.2", + "@typescript-eslint/parser": "^8.46.2", + "angular-eslint": "^20.5.0", + "eslint": "^9.39.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-jest": "^29.0.1", "eslint-plugin-prettier": "^5.5.4", - "globals": "^15.11.0", - "jest": "^29.7.0", + "globals": "^16.5.0", + "jest": "^30.2.0", "jest-canvas-mock": "^2.5.2", - "jest-preset-angular": "^14.6.0", - "minimist": "^1.2.5", - "prettier": "^3.3.3", + "jest-preset-angular": "^15.0.3", + "minimist": "^1.2.8", + "prettier": "^3.6.2", "ts-node": "~10.9.2", - "typescript": "~5.8.3", - "typescript-eslint": "^8.41.0" + "typescript": "~5.9.3", + "typescript-eslint": "^8.46.2" }, "optionalDependencies": { "@nx/nx-darwin-arm64": "21.2.0", - "@nx/nx-darwin-x64": "20.0.3", + "@nx/nx-darwin-x64": "21.6.5", "@nx/nx-linux-x64-gnu": "19.8.2", "@nx/nx-win32-x64-msvc": "19.8.4" }, diff --git a/teammapper-frontend/packages/mermaid-mindmap-parser/package.json b/teammapper-frontend/packages/mermaid-mindmap-parser/package.json index 7839e29f3..886b3932c 100644 --- a/teammapper-frontend/packages/mermaid-mindmap-parser/package.json +++ b/teammapper-frontend/packages/mermaid-mindmap-parser/package.json @@ -27,11 +27,11 @@ "dist" ], "dependencies": { - "dompurify": "3.2.4" + "dompurify": "3.3.0" }, "devDependencies": { - "typescript": "~5.8.3", + "typescript": "~5.9.3", "jison": "0.4.18", - "vite": "^6.3.5" + "vite": "^7.1.12" } } diff --git a/teammapper-frontend/playwright.config.ts b/teammapper-frontend/playwright.config.ts index 773e7ffe6..c1f64b032 100644 --- a/teammapper-frontend/playwright.config.ts +++ b/teammapper-frontend/playwright.config.ts @@ -44,7 +44,10 @@ export default defineConfig({ projects: [ { name: 'webkit', - use: { ...devices['Desktop Safari'] }, + use: { + ...devices['Desktop Safari'], + headless: true, // Force headless mode for Docker environment + }, }, ], outputDir: './playwright/output', @@ -53,15 +56,16 @@ export default defineConfig({ webServer: [ { port: 3000, - command: 'npm run --prefix ../teammapper-backend start', + command: 'pnpm --filter teammapper-backend start:dev', reuseExistingServer: !process.env.CI, stdout: 'pipe', stderr: 'pipe', timeout: 120 * 1000, // 2 minutes timeout + cwd: '..', }, { port: 4200, - command: 'npm run start', + command: 'pnpm run start', reuseExistingServer: !process.env.CI, stdout: 'pipe', stderr: 'pipe', diff --git a/teammapper-frontend/setup-jest.ts b/teammapper-frontend/setup-jest.ts index 5d72226ba..7d4093e47 100644 --- a/teammapper-frontend/setup-jest.ts +++ b/teammapper-frontend/setup-jest.ts @@ -1 +1,32 @@ import 'jest-canvas-mock'; +import 'zone.js'; +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserTestingModule, + platformBrowserTesting, +} from '@angular/platform-browser/testing'; + +// Polyfill TextEncoder/TextDecoder for Node.js test environment (required by jsPDF) +// In Node.js 18+, these are available globally, but jsdom doesn't provide them +if (typeof globalThis.TextEncoder === 'undefined') { + const { TextEncoder: NodeTextEncoder, TextDecoder: NodeTextDecoder } = + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('util') as { + TextEncoder: typeof TextEncoder; + TextDecoder: typeof TextDecoder; + }; + globalThis.TextEncoder = NodeTextEncoder; + globalThis.TextDecoder = NodeTextDecoder; +} + +// Initialize the Angular testing environment only once +// This prevents "Cannot set base providers because it has already been called" error +try { + getTestBed().initTestEnvironment( + BrowserTestingModule, + platformBrowserTesting() + ); +} catch (error) { + // TestBed already initialized, ignore +} diff --git a/teammapper-frontend/src/app/core/services/dialog/dialog.service.ts b/teammapper-frontend/src/app/core/services/dialog/dialog.service.ts index b635584ec..8741ea2a9 100644 --- a/teammapper-frontend/src/app/core/services/dialog/dialog.service.ts +++ b/teammapper-frontend/src/app/core/services/dialog/dialog.service.ts @@ -6,6 +6,10 @@ import { DialogImportMermaidComponent } from 'src/app/modules/application/compon import { DialogImportAiComponent } from 'src/app/modules/application/components/dialog-import-ai/dialog-import-ai.component'; import { DialogPictogramsComponent } from 'src/app/modules/application/components/dialog-pictograms/dialog-pictograms.component'; import { DialogShareComponent } from 'src/app/modules/application/components/dialog-share/dialog-share.component'; +import { + DialogCriticalErrorComponent, + CriticalErrorData, +} from 'src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component'; @Injectable({ providedIn: 'root', @@ -19,6 +23,7 @@ export class DialogService { private pictogramsModalRef: MatDialogRef; private importMermaidModalRef: MatDialogRef; private importAiModalRef: MatDialogRef; + private criticalErrorModalRef: MatDialogRef; openPictogramDialog() { this.pictogramsModalRef = this.dialog.open(DialogPictogramsComponent); @@ -84,4 +89,32 @@ export class DialogService { this.shareModalRef.close(); } + + /** + * Open critical error dialog + * This modal is blocking and cannot be dismissed except by reloading the page + * @param errorData Critical error data to display + * @returns Dialog reference + */ + openCriticalErrorDialog( + errorData: CriticalErrorData + ): MatDialogRef { + // Only open one critical error dialog at a time + if (this.criticalErrorModalRef) { + return this.criticalErrorModalRef; + } + + this.criticalErrorModalRef = this.dialog.open( + DialogCriticalErrorComponent, + { + data: errorData, + disableClose: true, // Prevent closing by clicking outside or pressing escape + hasBackdrop: true, + backdropClass: 'critical-error-backdrop', + panelClass: 'critical-error-dialog', + } + ); + + return this.criticalErrorModalRef; + } } diff --git a/teammapper-frontend/src/app/core/services/import/import.service.ts b/teammapper-frontend/src/app/core/services/import/import.service.ts index d13426948..a111e3b09 100644 --- a/teammapper-frontend/src/app/core/services/import/import.service.ts +++ b/teammapper-frontend/src/app/core/services/import/import.service.ts @@ -150,7 +150,7 @@ export class ImportService { return ''; } - const settings = this.settingsService.getCachedSettings(); + const settings = this.settingsService.getCachedUserSettings(); if (!settings) { return parentBranchColor; } @@ -202,7 +202,7 @@ export class ImportService { isRoot: boolean, branchColor: string ): ExportNodeProperties { - const settings = this.settingsService.getCachedSettings(); + const settings = this.settingsService.getCachedUserSettings(); if (!settings) { throw new Error('Settings not available'); } diff --git a/teammapper-frontend/src/app/core/services/map-sync/map-sync.service.spec.ts b/teammapper-frontend/src/app/core/services/map-sync/map-sync.service.spec.ts new file mode 100644 index 000000000..ca69191be --- /dev/null +++ b/teammapper-frontend/src/app/core/services/map-sync/map-sync.service.spec.ts @@ -0,0 +1,447 @@ +import { TestBed } from '@angular/core/testing'; +import { MapSyncService } from './map-sync.service'; +import { MmpService } from '../mmp/mmp.service'; +import { HttpService } from '../../http/http.service'; +import { StorageService } from '../storage/storage.service'; +import { SettingsService } from '../settings/settings.service'; +import { UtilsService } from '../utils/utils.service'; +import { ToastrService } from 'ngx-toastr'; +import { ToastService } from '../toast/toast.service'; +import { DialogService } from '../dialog/dialog.service'; +import { + ValidationErrorResponse, + CriticalErrorResponse, + SuccessResponse, + OperationResponse, +} from './server-types'; +import { ExportNodeProperties } from '@mmp/map/types'; +import { createMockUtilsService } from '../../../../test/mocks/utils-service.mock'; +import { Observable } from 'rxjs'; +import { UserSettings } from '../../../shared/models/settings.model'; + +// Mock the NodePropertyMapping module +jest.mock('@mmp/index', () => ({ + NodePropertyMapping: { + name: ['name'], + locked: ['locked'], + coordinates: ['coordinates'], + imageSrc: ['image', 'src'], + imageSize: ['image', 'size'], + linkHref: ['link', 'href'], + backgroundColor: ['colors', 'background'], + branchColor: ['colors', 'branch'], + fontWeight: ['font', 'weight'], + fontStyle: ['font', 'style'], + fontSize: ['font', 'size'], + nameColor: ['colors', 'name'], + hidden: ['hidden'], + }, +})); + +// Import NodePropertyMapping after mocking - needed for service to work +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { NodePropertyMapping } from '@mmp/index'; + +/** + * Type helper for accessing private members of MapSyncService in tests. + * Private methods contain important logic that needs unit testing. + */ +interface MapSyncServicePrivate { + socket: { + emit: jest.Mock; + removeAllListeners: jest.Mock; + on?: jest.Mock; + io?: { + on: jest.Mock; + }; + }; + getUserFriendlyErrorMessage: (code: string, msg: string) => Promise; +} + +/** + * Helper function to safely access private members of MapSyncService. + * Uses double cast to bypass TypeScript's protection of private members. + */ +function asPrivate(service: MapSyncService): MapSyncServicePrivate { + return service as unknown as MapSyncServicePrivate; +} + +/** + * Factory function to create fully-typed mock nodes. + * Ensures all required properties are present, preventing partial mock type assertions. + */ +function createMockNode( + overrides?: Partial +): ExportNodeProperties { + return { + id: 'mock-id', + name: 'Mock Node', + parent: 'root', + k: 1, + colors: { branch: '#000000' }, + font: { size: 14, style: 'normal', weight: 'normal' }, + locked: false, + hidden: false, + coordinates: undefined, + image: undefined, + link: undefined, + isRoot: false, + detached: false, + ...overrides, + }; +} + +describe('MapSyncService', () => { + let service: MapSyncService; + let mmpService: jest.Mocked; + let httpService: jest.Mocked; + let storageService: jest.Mocked; + let settingsService: jest.Mocked; + let utilsService: jest.Mocked; + let toastService: jest.Mocked; + let dialogService: jest.Mocked; + let toastrService: jest.Mocked; + + const mockNode: ExportNodeProperties = { + id: 'node-1', + name: 'Test Node', + parent: 'root', + k: 1, + colors: { branch: '#000000' }, + font: { size: 14, style: 'normal', weight: 'normal' }, + locked: false, + hidden: false, + coordinates: undefined, + image: undefined, + link: undefined, + isRoot: false, + detached: false, + }; + + const mockMapSnapshot: ExportNodeProperties[] = [mockNode]; + + const mockServerMap = { + uuid: 'test-uuid', + lastModified: new Date().toISOString(), + deletedAt: new Date(Date.now() + 86400000).toISOString(), + deleteAfterDays: 30, + data: mockMapSnapshot, + options: { fontMaxSize: 18, fontMinSize: 10, fontIncrement: 2 }, + createdAt: new Date().toISOString(), + }; + + beforeEach(() => { + // Only mock methods that are actually used in these tests + mmpService = { + new: jest.fn(), + selectNode: jest.fn(), + getRootNode: jest.fn(), + on: jest.fn(), + } as unknown as jest.Mocked; + + httpService = { + get: jest.fn(), + post: jest.fn(), + } as unknown as jest.Mocked; + + storageService = { + get: jest.fn(), + set: jest.fn(), + } as unknown as jest.Mocked; + + settingsService = { + getCachedUserSettings: jest.fn(), + } as unknown as jest.Mocked; + + toastService = { + showValidationCorrection: jest.fn(), + } as unknown as jest.Mocked; + + dialogService = { + openCriticalErrorDialog: jest.fn(), + } as unknown as jest.Mocked; + + toastrService = { + error: jest.fn(), + success: jest.fn(), + warning: jest.fn(), + } as unknown as jest.Mocked; + + // Create mock UtilsService using shared test utility + utilsService = createMockUtilsService(); + + const subscribeMock = jest.fn().mockReturnValue({ unsubscribe: jest.fn() }); + mmpService.on.mockReturnValue({ + subscribe: subscribeMock, + } as unknown as Observable); + + mmpService.getRootNode.mockReturnValue( + createMockNode({ id: 'root', name: 'Root', isRoot: true }) + ); + mmpService.selectNode.mockReturnValue(mockNode); + settingsService.getCachedUserSettings.mockReturnValue({ + mapOptions: { rootNode: 'Root' }, + } as unknown as UserSettings); + + TestBed.configureTestingModule({ + providers: [ + MapSyncService, + { provide: MmpService, useValue: mmpService }, + { provide: HttpService, useValue: httpService }, + { provide: StorageService, useValue: storageService }, + { provide: SettingsService, useValue: settingsService }, + { provide: UtilsService, useValue: utilsService }, + { provide: ToastService, useValue: toastService }, + { provide: DialogService, useValue: dialogService }, + { provide: ToastrService, useValue: toastrService }, + ], + }); + + service = TestBed.inject(MapSyncService); + }); + + afterEach(() => { + service.ngOnDestroy(); + }); + + describe('operation response handling', () => { + let handleResponse: (response: OperationResponse) => Promise; + + beforeEach(() => { + const emitSpy = jest.fn( + ( + _event: string, + _data: unknown, + callback?: (response: OperationResponse) => Promise + ) => { + if (callback) handleResponse = callback; + } + ); + + const socketSpy = { + emit: emitSpy, + removeAllListeners: jest.fn(), + }; + asPrivate(service).socket = socketSpy; + jest.spyOn(service, 'getAttachedMap').mockReturnValue({ + key: 'map-test', + cachedMap: { + uuid: 'test-uuid', + data: mockMapSnapshot, + lastModified: Date.now(), + createdAt: Date.now(), + deletedAt: Date.now() + 86400000, + deleteAfterDays: 30, + options: { fontMaxSize: 18, fontMinSize: 10, fontIncrement: 2 }, + }, + }); + + service.addNode(mockNode); + }); + + it('success response does nothing', async () => { + const successResponse: SuccessResponse = { + success: true, + data: [mockNode], + }; + + await handleResponse(successResponse); + + expect(mmpService.new).not.toHaveBeenCalled(); + expect(toastService.showValidationCorrection).not.toHaveBeenCalled(); + expect(dialogService.openCriticalErrorDialog).not.toHaveBeenCalled(); + }); + + it('error with fullMapState reloads map', async () => { + const errorResponse: ValidationErrorResponse = { + success: false, + errorType: 'validation', + code: 'INVALID_PARENT', + message: 'Invalid parent', + fullMapState: mockServerMap, + }; + + await handleResponse(errorResponse); + + expect(mmpService.new).toHaveBeenCalledWith(mockMapSnapshot, false); + }); + + it('error with fullMapState shows toast', async () => { + const errorResponse: CriticalErrorResponse = { + success: false, + errorType: 'critical', + code: 'SERVER_ERROR', + message: 'Server error', + fullMapState: mockServerMap, + }; + + await handleResponse(errorResponse); + + expect(toastService.showValidationCorrection).toHaveBeenCalledWith( + 'add node', + 'Operation failed - map reloaded from server' + ); + }); + + it('error without fullMapState shows critical dialog', async () => { + const errorResponse: CriticalErrorResponse = { + success: false, + errorType: 'critical', + code: 'SERVER_ERROR', + message: 'Server error', + }; + + await handleResponse(errorResponse); + + expect(dialogService.openCriticalErrorDialog).toHaveBeenCalledWith({ + code: 'SERVER_ERROR', + message: expect.stringContaining('server encountered an error'), + }); + }); + + it('malformed response shows critical dialog', async () => { + const malformedResponse = { + invalid: 'response', + } as unknown as OperationResponse; + + await handleResponse(malformedResponse); + + expect(dialogService.openCriticalErrorDialog).toHaveBeenCalledWith({ + code: 'MALFORMED_RESPONSE', + message: expect.stringContaining('invalid response'), + }); + }); + + it('malformed response with translation failure uses fallback message', async () => { + // Simulate translation service failure + utilsService.translate.mockImplementation(async () => { + throw new Error('Translation failed'); + }); + + const malformedResponse = { + invalid: 'response', + } as unknown as OperationResponse; + + await handleResponse(malformedResponse); + + expect(dialogService.openCriticalErrorDialog).toHaveBeenCalledWith({ + code: 'MALFORMED_RESPONSE', + message: 'Invalid server response. Please try again.', + }); + }); + + it('error with malformed fullMapState shows critical dialog', async () => { + const errorResponse: ValidationErrorResponse = { + success: false, + errorType: 'validation', + code: 'INVALID_PARENT', + message: 'Invalid parent', + fullMapState: { + // Missing required fields - malformed + uuid: 'test-uuid', + data: [], + } as unknown as typeof mockServerMap, + }; + + await handleResponse(errorResponse); + + // Should treat as malformed response since fullMapState is invalid + expect(dialogService.openCriticalErrorDialog).toHaveBeenCalledWith({ + code: 'MALFORMED_RESPONSE', + message: expect.stringContaining('invalid response'), + }); + expect(mmpService.new).not.toHaveBeenCalled(); + }); + + it('error without fullMapState with translation failure uses fallback', async () => { + // Simulate translation service failure + utilsService.translate.mockImplementation(async () => { + throw new Error('Translation failed'); + }); + + const errorResponse: CriticalErrorResponse = { + success: false, + errorType: 'critical', + code: 'SERVER_ERROR', + message: 'Server error', + }; + + await handleResponse(errorResponse); + + expect(dialogService.openCriticalErrorDialog).toHaveBeenCalledWith({ + code: 'SERVER_ERROR', + message: 'An error occurred. Please try again.', + }); + }); + }); + + describe('getUserFriendlyErrorMessage', () => { + it('returns user-friendly message for known codes', async () => { + const message = await asPrivate(service).getUserFriendlyErrorMessage( + 'SERVER_ERROR', + 'CRITICAL_ERROR.SERVER_ERROR' + ); + + expect(message).toContain('server encountered an error'); + }); + + it('returns default message for unknown codes', async () => { + const message = await asPrivate(service).getUserFriendlyErrorMessage( + 'UNKNOWN_CODE', + 'CRITICAL_ERROR.UNKNOWN' + ); + + expect(message).toContain('unexpected error occurred'); + }); + }); + + describe('map initialization', () => { + beforeEach(() => { + const mockCachedMapEntry = { + key: 'map-test-uuid', + cachedMap: { + uuid: 'test-uuid', + data: mockMapSnapshot, + lastModified: Date.now(), + createdAt: Date.now(), + deletedAt: Date.now() + 86400000, + deleteAfterDays: 30, + options: { fontMaxSize: 18, fontMinSize: 10, fontIncrement: 2 }, + }, + }; + + jest.spyOn(service, 'getAttachedMap').mockReturnValue(mockCachedMapEntry); + + const socketSpy = { + emit: jest.fn(), + on: jest.fn().mockReturnThis(), + removeAllListeners: jest.fn(), + io: { + on: jest.fn().mockReturnThis(), + }, + }; + + asPrivate(service).socket = socketSpy; + }); + + it('loads map data into mmpService on initMap', () => { + service.initMap(); + + expect(mmpService.new).toHaveBeenCalledWith(mockMapSnapshot); + }); + + it('selects root node on initMap', () => { + const rootNode = createMockNode({ + id: 'root', + name: 'Root', + isRoot: true, + }); + mmpService.getRootNode.mockReturnValue(rootNode); + mmpService.selectNode.mockReturnValue(rootNode); + + service.initMap(); + + expect(mmpService.selectNode).toHaveBeenCalledWith('root'); + }); + }); +}); diff --git a/teammapper-frontend/src/app/core/services/map-sync/map-sync.service.ts b/teammapper-frontend/src/app/core/services/map-sync/map-sync.service.ts index 611fdc773..8ab201d5e 100644 --- a/teammapper-frontend/src/app/core/services/map-sync/map-sync.service.ts +++ b/teammapper-frontend/src/app/core/services/map-sync/map-sync.service.ts @@ -2,6 +2,7 @@ import { Injectable, OnDestroy, inject } from '@angular/core'; import { MmpService } from '../mmp/mmp.service'; import { BehaviorSubject, Observable } from 'rxjs'; import { + CachedAdminMapEntry, CachedAdminMapValue, CachedMap, CachedMapEntry, @@ -25,8 +26,12 @@ import { ResponseSelectionUpdated, ResponseClientNotification, ServerMap, + ServerMapInfo, ResponseUndoRedoChanges, ReversePropertyMapping, + OperationResponse, + ValidationErrorResponse, + CriticalErrorResponse, } from './server-types'; import { API_URL, HttpService } from '../../http/http.service'; import { COLORS } from '../mmp/mmp-utils'; @@ -35,6 +40,8 @@ import { StorageService } from '../storage/storage.service'; import { SettingsService } from '../settings/settings.service'; import { ToastrService } from 'ngx-toastr'; import { MapDiff } from '@mmp/map/handlers/history'; +import { ToastService } from '../toast/toast.service'; +import { DialogService } from '../dialog/dialog.service'; const DEFAULT_COLOR = '#000000'; const DEFAULT_SELF_COLOR = '#c0c0c0'; @@ -60,6 +67,8 @@ export class MapSyncService implements OnDestroy { private settingsService = inject(SettingsService); utilsService = inject(UtilsService); toastrService = inject(ToastrService); + private toastService = inject(ToastService); + private dialogService = inject(DialogService); // needed in color panel to show all clients private readonly clientListSubject: BehaviorSubject; @@ -118,10 +127,22 @@ export class MapSyncService implements OnDestroy { this.reset(); } + /** + * Creates a new map on server and prepares it locally + * Stores admin data and enables edit mode + */ public async prepareNewMap(): Promise { const privateServerMap: PrivateServerMap = await this.postMapToServer(); + this.storePrivateMapData(privateServerMap); + this.setupNewMapState(privateServerMap); + return privateServerMap; + } + + /** + * Store private map data locally for admin access + */ + private storePrivateMapData(privateServerMap: PrivateServerMap): void { const serverMap = privateServerMap.map; - // store private map data locally this.storageService.set(serverMap.uuid, { adminId: privateServerMap.adminId, modificationSecret: privateServerMap.modificationSecret, @@ -129,12 +150,15 @@ export class MapSyncService implements OnDestroy { rootName: serverMap.data[0].name, createdAt: serverMap.createdAt, }); + } - this.prepareMap(serverMap); - + /** + * Setup state for newly created map + */ + private setupNewMapState(privateServerMap: PrivateServerMap): void { + this.prepareMap(privateServerMap.map); this.settingsService.setEditMode(true); this.modificationSecret = privateServerMap.modificationSecret; - return privateServerMap; } public async prepareExistingMap( @@ -226,7 +250,10 @@ export class MapSyncService implements OnDestroy { public async joinMap(mmpUuid: string, color: string): Promise { return await new Promise( - (resolve: (reason: any) => void, reject: (reason: any) => void) => { + ( + resolve: (value: MapProperties) => void, + reject: (reason: string) => void + ) => { this.socket.emit( 'join', { mapId: mmpUuid, color }, @@ -247,45 +274,97 @@ export class MapSyncService implements OnDestroy { } public addNode(newNode: ExportNodeProperties) { - this.socket.emit('addNodes', { - mapId: this.getAttachedMap().cachedMap.uuid, - nodes: [newNode], - modificationSecret: this.modificationSecret, - }); + // Emit with acknowledgment callback for error handling + this.socket.emit( + 'addNodes', + { + mapId: this.getAttachedMap().cachedMap.uuid, + nodes: [newNode], + modificationSecret: this.modificationSecret, + }, + async (response: OperationResponse) => { + await this.handleOperationResponse(response, 'add node'); + } + ); } + /** + * Add multiple nodes with server validation and error handling + * Used for bulk operations like paste + */ public addNodes(newNodes: ExportNodeProperties[]) { - this.socket.emit('addNodes', { - mapId: this.getAttachedMap().cachedMap.uuid, - nodes: newNodes, - modificationSecret: this.modificationSecret, - }); + // Emit with acknowledgment callback for error handling + this.socket.emit( + 'addNodes', + { + mapId: this.getAttachedMap().cachedMap.uuid, + nodes: newNodes, + modificationSecret: this.modificationSecret, + }, + async (response: OperationResponse) => { + await this.handleOperationResponse(response, 'add nodes'); + } + ); } + /** + * Update node property with server validation and error handling + */ public updateNode(nodeUpdate: NodeUpdateEvent) { - this.socket.emit('updateNode', { - mapId: this.getAttachedMap().cachedMap.uuid, - node: nodeUpdate.nodeProperties, - updatedProperty: nodeUpdate.changedProperty, - modificationSecret: this.modificationSecret, - }); + // Emit with acknowledgment callback for error handling + this.socket.emit( + 'updateNode', + { + mapId: this.getAttachedMap().cachedMap.uuid, + node: nodeUpdate.nodeProperties, + updatedProperty: nodeUpdate.changedProperty, + modificationSecret: this.modificationSecret, + }, + async (response: OperationResponse) => { + await this.handleOperationResponse(response, 'update node'); + } + ); } + /** + * Remove node with server validation and error handling + */ public removeNode(removedNode: ExportNodeProperties) { - this.socket.emit('removeNode', { - mapId: this.getAttachedMap().cachedMap.uuid, - node: removedNode, - modificationSecret: this.modificationSecret, - }); + // Emit with acknowledgment callback for error handling + this.socket.emit( + 'removeNode', + { + mapId: this.getAttachedMap().cachedMap.uuid, + node: removedNode, + modificationSecret: this.modificationSecret, + }, + async (response: OperationResponse) => { + await this.handleOperationResponse(response, 'remove node'); + } + ); } - public applyMapChangesByDiff(diff: MapDiff) { + /** + * Apply undo/redo changes with server validation and error handling + */ + public applyMapChangesByDiff(diff: MapDiff, operationType: 'undo' | 'redo') { const cachedMapEntry: CachedMapEntry = this.getAttachedMap(); - this.socket.emit('applyMapChangesByDiff', { - mapId: cachedMapEntry.cachedMap.uuid, - diff, - modificationSecret: this.modificationSecret, - }); + + // Emit with acknowledgment callback for error handling + this.socket.emit( + 'applyMapChangesByDiff', + { + mapId: cachedMapEntry.cachedMap.uuid, + diff, + modificationSecret: this.modificationSecret, + }, + async (response: OperationResponse) => { + await this.handleOperationResponse( + response, + `${operationType} operation` + ); + } + ); } public updateMap() { @@ -306,13 +385,13 @@ export class MapSyncService implements OnDestroy { }); } - public async deleteMap(adminId: string): Promise { + public async deleteMap(adminId: string): Promise { const cachedMapEntry: CachedMapEntry = this.getAttachedMap(); const body: { adminId: string; mapId: string } = { adminId, mapId: cachedMapEntry.cachedMap.uuid, }; - return this.socket.emit('deleteMap', body); + this.socket.emit('deleteMap', body); } public async updateNodeSelection(id: string, selected: boolean) { @@ -357,12 +436,30 @@ export class MapSyncService implements OnDestroy { return json; } + public async fetchUserMapsFromServer(): Promise { + const response = await this.httpService.get(API_URL.ROOT, '/maps'); + if (!response.ok) return []; + const json: ServerMapInfo[] = await response.json(); + const mapEntries: CachedAdminMapEntry[] = json.map(map => ({ + id: map.uuid, + cachedAdminMapValue: { + createdAt: map.createdAt ? new Date(map.createdAt) : null, + adminId: map.adminId, + modificationSecret: map.modificationSecret, + ttl: map.ttl ? new Date(map.ttl) : new Date(), + rootName: map.rootName, + }, + })); + return mapEntries; + } + private async postMapToServer(): Promise { const response = await this.httpService.post( API_URL.ROOT, '/maps/', JSON.stringify({ - rootNode: this.settingsService.getCachedSettings().mapOptions.rootNode, + rootNode: + this.settingsService.getCachedUserSettings().mapOptions.rootNode, }) ); @@ -387,210 +484,380 @@ export class MapSyncService implements OnDestroy { }); } + /** + * Setup all server event listeners and join the map + * Orchestrates socket event handlers for real-time collaboration + */ private listenServerEvents(uuid: string): Promise { this.checkModificationSecret(); + this.setupReconnectionHandler(uuid); + this.setupNotificationHandlers(); + this.setupNodeEventHandlers(); + this.setupMapEventHandlers(); + this.setupClientEventHandlers(); + this.setupConnectionEventHandlers(); + + return this.joinMap(uuid, this.clientColor); + } + /** + * Setup socket reconnection handler + * Re-joins map and syncs state on reconnect + */ + private setupReconnectionHandler(uuid: string): void { this.socket.io.on('reconnect', async () => { const serverMap: MapProperties = await this.joinMap( uuid, this.clientColor ); - this.setConnectionStatusSubject('connected'); this.mmpService.new(serverMap.data, false); }); + } + /** + * Setup notification event handlers + * Displays toasts for client notifications from server + */ + private setupNotificationHandlers(): void { this.socket.on( 'clientNotification', async (notification: ResponseClientNotification) => { if (notification.clientId === this.socket.id) return; - - const msg = await this.utilsService.translate(notification.message); - - if (!msg) return; - - switch (notification.type) { - case 'error': - this.toastrService.error(msg); - break; - case 'success': - this.toastrService.success(msg); - break; - case 'warning': - this.toastrService.warning(msg); - break; - } + await this.handleClientNotification(notification); } ); + } + + /** + * Handle individual client notification + * Translates message and shows appropriate toast type + */ + private async handleClientNotification( + notification: ResponseClientNotification + ): Promise { + const msg = await this.utilsService.translate(notification.message); + if (!msg) return; + + const toastHandlers = { + error: () => this.toastrService.error(msg), + success: () => this.toastrService.success(msg), + warning: () => this.toastrService.warning(msg), + }; + toastHandlers[notification.type]?.(); + } + + /** + * Setup node-related event handlers + * Handles node additions, updates, and removals + */ + private setupNodeEventHandlers(): void { + this.setupNodesAddedHandler(); + this.setupNodeUpdatedHandler(); + this.setupNodeRemovedHandler(); + } + /** + * Setup handler for nodes being added + */ + private setupNodesAddedHandler(): void { this.socket.on('nodesAdded', (result: ResponseNodesAdded) => { if (result.clientId === this.socket.id) return; - this.mmpService.addNodesFromServer(result.nodes); }); + } + /** + * Setup handler for node property updates + */ + private setupNodeUpdatedHandler(): void { this.socket.on('nodeUpdated', (result: ResponseNodeUpdated) => { if (result.clientId === this.socket.id) return; + this.handleNodeUpdate(result); + }); + } - const newNode = result.node; - const existingNode = this.mmpService.getNode(newNode.id); - const propertyPath = NodePropertyMapping[result.property]; - const changedValue = UtilsService.get(newNode, propertyPath); - - this.mmpService.updateNode( - result.property, - changedValue, - false, - true, - existingNode.id - ); + /** + * Handle individual node property update + */ + private handleNodeUpdate(result: ResponseNodeUpdated): void { + const newNode = result.node; + const existingNode = this.mmpService.getNode(newNode.id); + const propertyPath = NodePropertyMapping[result.property]; + const changedValue = UtilsService.get(newNode, propertyPath); + + this.mmpService.updateNode( + result.property, + changedValue, + false, + true, + existingNode.id + ); + } + + /** + * Setup handler for node removal + */ + private setupNodeRemovedHandler(): void { + this.socket.on('nodeRemoved', (result: ResponseNodeRemoved) => { + if (result.clientId === this.socket.id) return; + const removedNodeId = result.nodeId; + if (this.mmpService.existNode(removedNodeId)) { + this.mmpService.removeNode(removedNodeId, false); + } }); + } + /** + * Setup map-related event handlers + * Handles map updates, undo/redo, and options + */ + private setupMapEventHandlers(): void { + this.setupMapUpdatedHandler(); + this.setupMapChangesHandler(); + this.setupMapOptionsHandler(); + this.setupMapDeletedHandler(); + } + + /** + * Setup handler for full map updates + */ + private setupMapUpdatedHandler(): void { this.socket.on('mapUpdated', (result: ResponseMapUpdated) => { if (result.clientId === this.socket.id) return; - this.mmpService.new(result.map.data, false); }); + } + /** + * Setup handler for map undo/redo changes + */ + private setupMapChangesHandler(): void { this.socket.on('mapChangesUndoRedo', (result: ResponseUndoRedoChanges) => { if (result.clientId === this.socket.id) return; + this.applyMapDiff(result.diff); + }); + } - const getClientProperty = ( - serverProperty: string, - value: any - ): { clientProperty: string; directValue: any } => { - const mapping = - ReversePropertyMapping[ - serverProperty as keyof typeof ReversePropertyMapping - ]; - - if (typeof mapping === 'string') { - return { - clientProperty: mapping, - directValue: value, - }; - } - - if (mapping && typeof value === 'object') { - const subProperty = Object.keys(value)[0]; - const nestedMapping = mapping[subProperty]; - - return { - clientProperty: nestedMapping, - directValue: value[subProperty], - }; - } + /** + * Apply map diff for undo/redo operations + */ + private applyMapDiff(diff: MapDiff): void { + const { added, updated, deleted } = diff; - return; - }; + this.applyAddedNodes(added); + this.applyUpdatedNodes(updated); + this.applyDeletedNodes(deleted); + } - const { added, updated, deleted } = result.diff; + /** + * Apply added nodes from diff + */ + private applyAddedNodes(added: unknown): void { + if (added && typeof added === 'object') { + for (const nodeId in added) { + const node = added[nodeId]; + this.mmpService.addNode(node, false); + } + } + } - // Handle added nodes - if (added && typeof added === 'object') { - for (const nodeId in added) { - const node = added[nodeId]; - this.mmpService.addNode(node, false); + /** + * Apply updated nodes from diff + */ + private applyUpdatedNodes(updated: unknown): void { + if (updated && typeof updated === 'object') { + for (const nodeId in updated) { + const node = updated[nodeId]; + if (this.mmpService.existNode(nodeId)) { + this.applyNodePropertyUpdates(nodeId, node); } } + } + } - // Handle updated nodes - if (updated && typeof updated === 'object') { - for (const nodeId in updated) { - const node = updated[nodeId]; - if (this.mmpService.existNode(nodeId)) { - for (const property in node) { - const updatedProperty = getClientProperty( - property, - node[property] - ); - - this.mmpService.updateNode( - updatedProperty.clientProperty, - updatedProperty.directValue, - false, // notifyWithEvent - true, // updateHistory - nodeId - ); - } - } - } + /** + * Apply property updates to a single node + */ + private applyNodePropertyUpdates(nodeId: string, nodeUpdates: unknown): void { + if (typeof nodeUpdates !== 'object' || !nodeUpdates) return; + + for (const property in nodeUpdates as Record) { + const updatedProperty = this.getClientProperty( + property, + (nodeUpdates as Record)[property] + ); + if (updatedProperty) { + this.mmpService.updateNode( + updatedProperty.clientProperty, + updatedProperty.directValue, + false, + true, + nodeId + ); } + } + } - // Handle deleted nodes - if (deleted && typeof deleted === 'object') { - for (const nodeId in deleted) { - if (this.mmpService.existNode(nodeId)) { - this.mmpService.removeNode(nodeId, false); - } + /** + * Convert server property to client property format + */ + private getClientProperty( + serverProperty: string, + value: unknown + ): { clientProperty: string; directValue: unknown } | undefined { + const mapping = + ReversePropertyMapping[ + serverProperty as keyof typeof ReversePropertyMapping + ]; + + if (typeof mapping === 'string') { + return { clientProperty: mapping, directValue: value }; + } + + if (mapping && typeof value === 'object') { + const subProperty = Object.keys(value)[0]; + const nestedMapping = mapping[subProperty]; + return { + clientProperty: nestedMapping, + directValue: value[subProperty], + }; + } + + return; + } + + /** + * Apply deleted nodes from diff + */ + private applyDeletedNodes(deleted: unknown): void { + if (deleted && typeof deleted === 'object') { + for (const nodeId in deleted) { + if (this.mmpService.existNode(nodeId)) { + this.mmpService.removeNode(nodeId, false); } } - }); + } + } + /** + * Setup handler for map options updates + */ + private setupMapOptionsHandler(): void { this.socket.on('mapOptionsUpdated', (result: ResponseMapOptionsUpdated) => { if (result.clientId === this.socket.id) return; - this.mmpService.updateAdditionalMapOptions(result.options); }); + } - this.socket.on('nodeRemoved', (result: ResponseNodeRemoved) => { - if (result.clientId === this.socket.id) return; - - const removedNodeId = result.nodeId; - if (this.mmpService.existNode(removedNodeId)) { - this.mmpService.removeNode(removedNodeId, false); - } + /** + * Setup handler for map deletion + */ + private setupMapDeletedHandler(): void { + this.socket.on('mapDeleted', () => { + window.location.reload(); }); + } + /** + * Setup client-related event handlers + * Handles selection updates and client list changes + */ + private setupClientEventHandlers(): void { + this.setupSelectionHandler(); + this.setupClientListHandler(); + this.setupClientDisconnectHandler(); + } + + /** + * Setup handler for selection updates + */ + private setupSelectionHandler(): void { this.socket.on('selectionUpdated', (result: ResponseSelectionUpdated) => { if (result.clientId === this.socket.id) return; if (!this.mmpService.existNode(result.nodeId)) return; + this.handleSelectionUpdate(result); + }); + } - if (!this.colorMapping[result.clientId]) { - this.colorMapping[result.clientId] = { - color: DEFAULT_COLOR, - nodeId: '', - }; - this.extractClientListForSubscriber(); - } + /** + * Handle individual selection update + */ + private handleSelectionUpdate(result: ResponseSelectionUpdated): void { + this.ensureClientInMapping(result.clientId); + this.updateClientNodeSelection( + result.clientId, + result.nodeId, + result.selected + ); + const colorForNode: string = this.colorForNode(result.nodeId); + this.mmpService.highlightNode(result.nodeId, colorForNode, false); + } - if (result.selected) { - this.colorMapping[result.clientId].nodeId = result.nodeId; - } else { - this.colorMapping[result.clientId].nodeId = ''; - } - const colorForNode: string = this.colorForNode(result.nodeId); - this.mmpService.highlightNode(result.nodeId, colorForNode, false); - }); + /** + * Ensure client exists in color mapping + */ + private ensureClientInMapping(clientId: string): void { + if (!this.colorMapping[clientId]) { + this.colorMapping[clientId] = { color: DEFAULT_COLOR, nodeId: '' }; + this.extractClientListForSubscriber(); + } + } + /** + * Update client's selected node in mapping + */ + private updateClientNodeSelection( + clientId: string, + nodeId: string, + selected: boolean + ): void { + this.colorMapping[clientId].nodeId = selected ? nodeId : ''; + } + + /** + * Setup handler for client list updates + */ + private setupClientListHandler(): void { this.socket.on('clientListUpdated', (clients: ServerClientList) => { - this.colorMapping = Object.keys(clients).reduce( - (acc: ClientColorMapping, key: string) => { - acc[key] = { - nodeId: this.colorMapping[key]?.nodeId || '', - color: key === this.socket.id ? DEFAULT_SELF_COLOR : clients[key], - }; - return acc; - }, - {} - ); + this.updateColorMapping(clients); this.extractClientListForSubscriber(); }); + } + + /** + * Update color mapping from server client list + */ + private updateColorMapping(clients: ServerClientList): void { + this.colorMapping = Object.keys(clients).reduce( + (acc: ClientColorMapping, key: string) => { + acc[key] = { + nodeId: this.colorMapping[key]?.nodeId || '', + color: key === this.socket.id ? DEFAULT_SELF_COLOR : clients[key], + }; + return acc; + }, + {} + ); + } + /** + * Setup handler for client disconnection + */ + private setupClientDisconnectHandler(): void { this.socket.on('clientDisconnect', (clientId: string) => { delete this.colorMapping[clientId]; this.extractClientListForSubscriber(); }); + } + /** + * Setup connection event handlers + */ + private setupConnectionEventHandlers(): void { this.socket.on('disconnect', () => { this.setConnectionStatusSubject('disconnected'); }); - - this.socket.on('mapDeleted', () => { - window.location.reload(); - }); - - return this.joinMap(uuid, this.clientColor); } private colorForNode(nodeId: string): string { @@ -635,6 +902,145 @@ export class MapSyncService implements OnDestroy { } } + /** + * Validate ServerMap structure at runtime + * Ensures fullMapState has required properties before using + */ + private isValidServerMap(map: unknown): map is ServerMap { + if (!map || typeof map !== 'object') return false; + + const serverMap = map as ServerMap; + + return ( + typeof serverMap.uuid === 'string' && + serverMap.uuid.length > 0 && + Array.isArray(serverMap.data) && + serverMap.data.length > 0 && + typeof serverMap.lastModified === 'string' && + typeof serverMap.createdAt === 'string' && + typeof serverMap.deletedAt === 'string' && + typeof serverMap.deleteAfterDays === 'number' && + typeof serverMap.options === 'object' + ); + } + + /** + * Type guard to validate error response structure at runtime + */ + private isValidErrorResponse( + response: OperationResponse + ): response is ValidationErrorResponse | CriticalErrorResponse { + if (response.success !== false) return false; + + const errorResponse = response as + | ValidationErrorResponse + | CriticalErrorResponse; + + const isBasicStructureValid = + typeof errorResponse.errorType === 'string' && + (errorResponse.errorType === 'validation' || + errorResponse.errorType === 'critical') && + typeof errorResponse.code === 'string' && + errorResponse.code.trim() !== '' && + typeof errorResponse.message === 'string'; + + if (!isBasicStructureValid) return false; + + // Validate fullMapState if present + if (errorResponse.fullMapState) { + return this.isValidServerMap(errorResponse.fullMapState); + } + + return true; + } + + /** + * Simplified handler for all operation responses + * If error with fullMapState, reload from server state + */ + private async handleOperationResponse( + response: OperationResponse, + operationName: string + ): Promise { + // Success - operation confirmed by server + if (response.success) { + return; + } + + // Validate error response structure before processing + if (!this.isValidErrorResponse(response)) { + let malformedResponseMessage: string; + try { + malformedResponseMessage = await this.utilsService.translate( + 'TOASTS.ERRORS.MALFORMED_RESPONSE' + ); + } catch { + malformedResponseMessage = 'Invalid server response. Please try again.'; + } + this.dialogService.openCriticalErrorDialog({ + code: 'MALFORMED_RESPONSE', + message: malformedResponseMessage, + }); + return; + } + + // Error occurred - reload from fullMapState if available + if (response.fullMapState) { + // Reload entire map from server's authoritative state + this.mmpService.new(response.fullMapState.data, false); + + // Show appropriate error notification + let operationFailedMessage: string; + try { + operationFailedMessage = await this.utilsService.translate( + 'TOASTS.ERRORS.OPERATION_FAILED_MAP_RELOADED' + ); + } catch { + operationFailedMessage = 'Operation failed - map reloaded'; + } + this.toastService.showValidationCorrection( + `${operationName}`, + operationFailedMessage + ); + } else { + // No fullMapState provided - show critical error + const userMessage = await this.getUserFriendlyErrorMessage( + response.code || 'SERVER_ERROR', + response.message || 'Unknown error' + ); + + this.dialogService.openCriticalErrorDialog({ + code: response.code || 'SERVER_ERROR', + message: userMessage, + }); + } + } + + /** + * Convert error code to user-friendly translated message + */ + private async getUserFriendlyErrorMessage( + code: string, + _messageKey: string + ): Promise { + const errorKeyMapping: Record = { + NETWORK_TIMEOUT: 'TOASTS.ERRORS.NETWORK_TIMEOUT', + SERVER_ERROR: 'TOASTS.ERRORS.SERVER_ERROR', + AUTH_FAILED: 'TOASTS.ERRORS.AUTH_FAILED', + MALFORMED_REQUEST: 'TOASTS.ERRORS.MALFORMED_REQUEST', + RATE_LIMIT_EXCEEDED: 'TOASTS.ERRORS.RATE_LIMIT_EXCEEDED', + }; + + const translationKey = + errorKeyMapping[code] || 'TOASTS.ERRORS.UNEXPECTED_ERROR'; + + try { + return await this.utilsService.translate(translationKey); + } catch { + return 'An error occurred. Please try again.'; + } + } + private createMapListeners() { // create is NOT called by the mmp lib for initial map load / and call, but for _imported_ maps this.mmpService.on('create').subscribe((_result: MapCreateEvent) => { @@ -668,19 +1074,20 @@ export class MapSyncService implements OnDestroy { this.attachedNodeSubject.next(this.mmpService.selectNode()); // Updating the attached map is important because this persists changes after refresh this.updateAttachedMap(); - this.applyMapChangesByDiff(diff); + this.applyMapChangesByDiff(diff, 'undo'); }); this.mmpService.on('redo').subscribe((diff?: MapDiff) => { this.attachedNodeSubject.next(this.mmpService.selectNode()); // Updating the attached map is important because this persists changes after refresh this.updateAttachedMap(); - this.applyMapChangesByDiff(diff); + this.applyMapChangesByDiff(diff, 'redo'); }); this.mmpService .on('nodeCreate') .subscribe((newNode: ExportNodeProperties) => { + // Send node creation to server for validation this.addNode(newNode); this.updateAttachedMap(); this.mmpService.selectNode(newNode.id); @@ -690,6 +1097,7 @@ export class MapSyncService implements OnDestroy { this.mmpService .on('nodePaste') .subscribe((newNodes: ExportNodeProperties[]) => { + // Send bulk paste operations to server for validation this.addNodes(newNodes); this.updateAttachedMap(); }); @@ -697,6 +1105,7 @@ export class MapSyncService implements OnDestroy { this.mmpService .on('nodeRemove') .subscribe((removedNode: ExportNodeProperties) => { + // Send node removal to server for validation this.removeNode(removedNode); this.updateAttachedMap(); }); diff --git a/teammapper-frontend/src/app/core/services/map-sync/server-types.ts b/teammapper-frontend/src/app/core/services/map-sync/server-types.ts index 00da8b334..91c8be843 100644 --- a/teammapper-frontend/src/app/core/services/map-sync/server-types.ts +++ b/teammapper-frontend/src/app/core/services/map-sync/server-types.ts @@ -1,6 +1,69 @@ import { MapSnapshot, ExportNodeProperties } from '@mmp/map/types'; import { CachedMapOptions } from 'src/app/shared/models/cached-map.model'; +// Re-export operation types from backend +export type OperationType = + | 'create' + | 'update' + | 'delete' + | 'updateProperty' + | 'undo' + | 'redo'; +export type OperationStatus = 'pending' | 'confirmed' | 'rejected'; + +// Error response types (matching backend types.ts) +export interface BaseErrorResponse { + success: false; + errorType: 'validation' | 'critical'; + code: string; + message: string; + context?: Record; +} + +export interface ValidationErrorResponse extends BaseErrorResponse { + errorType: 'validation'; + code: + | 'INVALID_PARENT' + | 'CONSTRAINT_VIOLATION' + | 'MISSING_REQUIRED_FIELD' + | 'CIRCULAR_REFERENCE' + | 'DUPLICATE_NODE'; + fullMapState?: ServerMap; +} + +export interface CriticalErrorResponse extends BaseErrorResponse { + errorType: 'critical'; + code: + | 'SERVER_ERROR' + | 'NETWORK_TIMEOUT' + | 'AUTH_FAILED' + | 'MALFORMED_REQUEST' + | 'RATE_LIMIT_EXCEEDED'; + retryAfter?: number; + fullMapState?: ServerMap; +} + +export interface SuccessResponse { + success: true; + data: T; + meta?: { + timestamp: number; + operationId?: string; + }; +} + +export type OperationResponse = + | SuccessResponse + | ValidationErrorResponse + | CriticalErrorResponse; + +// Extended node properties with optimistic state +export interface ExportNodePropertiesWithState extends ExportNodeProperties { + __optimistic?: boolean; + __operationId?: string; + __localModifiedAt?: number; +} + interface ResponseServer { // socket id of the triggering client, to prevent endless update loops clientId: string; @@ -69,6 +132,15 @@ interface PrivateServerMap { modificationSecret: string; } +interface ServerMapInfo { + uuid: string; + adminId: string | null; + modificationSecret: string | null; + ttl: string | null; + createdAt: string | null; + rootName: string | null; +} + const ReversePropertyMapping = { name: 'name', locked: 'locked', @@ -103,6 +175,7 @@ export { ResponseSelectionUpdated, ResponseClientNotification, ServerMap, + ServerMapInfo, PrivateServerMap, ReversePropertyMapping, }; diff --git a/teammapper-frontend/src/app/core/services/mmp/mmp.service.spec.ts b/teammapper-frontend/src/app/core/services/mmp/mmp.service.spec.ts index 7b0ba686c..ce3184db9 100644 --- a/teammapper-frontend/src/app/core/services/mmp/mmp.service.spec.ts +++ b/teammapper-frontend/src/app/core/services/mmp/mmp.service.spec.ts @@ -78,16 +78,18 @@ describe('MmpService', () => { settingsService = { getEditModeObservable: jest.fn().mockReturnValue(editModeSubject), - getCachedSettings: jest.fn().mockReturnValue({ + getCachedUserSettings: jest.fn().mockReturnValue({ mapOptions: { autoBranchColors: false, }, }), getDefaultSettings: jest.fn().mockResolvedValue({ - mapOptions: { - fontMinSize: 12, - fontMaxSize: 24, - fontIncrement: 2, + userSettings: { + mapOptions: { + fontMinSize: 12, + fontMaxSize: 24, + fontIncrement: 2, + }, }, }), }; diff --git a/teammapper-frontend/src/app/core/services/mmp/mmp.service.ts b/teammapper-frontend/src/app/core/services/mmp/mmp.service.ts index 24fceb898..bcf6224fb 100644 --- a/teammapper-frontend/src/app/core/services/mmp/mmp.service.ts +++ b/teammapper-frontend/src/app/core/services/mmp/mmp.service.ts @@ -222,7 +222,7 @@ export class MmpService implements OnDestroy { if (this.selectNode()?.detached) { return; } - const settings = this.settingsService.getCachedSettings(); + const settings = this.settingsService.getCachedUserSettings(); if (properties?.colors?.branch) { newProps.colors = { @@ -599,7 +599,8 @@ export class MmpService implements OnDestroy { * Initialize additional map settings with defaults */ private async defaultAdditionalOptions(): Promise { - const defaultSettings = await this.settingsService.getDefaultSettings(); + const defaultSettings = (await this.settingsService.getDefaultSettings()) + .userSettings; return { fontMinSize: defaultSettings.mapOptions.fontMinSize, diff --git a/teammapper-frontend/src/app/core/services/pictograms/pictogram.service.ts b/teammapper-frontend/src/app/core/services/pictograms/pictogram.service.ts index b6dfe9b95..19f4dc60a 100644 --- a/teammapper-frontend/src/app/core/services/pictograms/pictogram.service.ts +++ b/teammapper-frontend/src/app/core/services/pictograms/pictogram.service.ts @@ -2,7 +2,6 @@ import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs/internal/Observable'; import { IPictogramResponse } from './picto-types'; -import { environment } from 'src/environments/environment'; import { SettingsService } from '../settings/settings.service'; @Injectable({ @@ -12,15 +11,20 @@ export class PictogramService { private http = inject(HttpClient); private settingsSerivce = inject(SettingsService); - private apirUrl = - environment.pictogramApiUrl || 'https://api.arasaac.org/v1/pictograms'; - private staticAssetUrl = - environment.pictogramStaticUrl || 'https://static.arasaac.org/pictograms'; + private apirUrl = 'https://api.arasaac.org/v1/pictograms'; + private staticAssetUrl = 'https://static.arasaac.org/pictograms'; private apiResource = 'search'; + constructor() { + const settings = this.settingsSerivce.getCachedSystemSettings(); + this.apirUrl = settings?.urls?.pictogramApiUrl || this.apirUrl; + this.staticAssetUrl = + settings?.urls?.pictogramStaticUrl || this.staticAssetUrl; + } + getPictos(seachTerm: string): Observable { const language = - this.settingsSerivce.getCachedSettings()?.general?.language || 'en'; + this.settingsSerivce.getCachedUserSettings()?.general?.language || 'en'; const url = `${this.apirUrl}/${language}/${this.apiResource}/${seachTerm}`; return this.http.get(url); } diff --git a/teammapper-frontend/src/app/core/services/settings/settings.service.spec.ts b/teammapper-frontend/src/app/core/services/settings/settings.service.spec.ts index 8a2e7b40e..06b0b9251 100644 --- a/teammapper-frontend/src/app/core/services/settings/settings.service.spec.ts +++ b/teammapper-frontend/src/app/core/services/settings/settings.service.spec.ts @@ -112,7 +112,7 @@ describe('SettingsService', () => { // Additional tests for full coverage describe('init', () => { it('initializes settings with default values when no cached settings exist', async () => { - const defaultSettings = { general: { language: 'en' } }; + const defaultSettings = { userSettings: { general: { language: 'en' } } }; httpService.get.mockResolvedValue({ json: () => Promise.resolve(defaultSettings), @@ -123,12 +123,12 @@ describe('SettingsService', () => { expect(storageService.set).toHaveBeenCalledWith( 'settings', - defaultSettings + defaultSettings.userSettings ); }); it('initializes settings with cached values when they exist', async () => { - const defaultSettings = { general: { language: 'en' } }; + const defaultSettings = { userSettings: { general: { language: 'en' } } }; const cachedSettings = { general: { language: 'fr' } }; httpService.get.mockResolvedValue({ diff --git a/teammapper-frontend/src/app/core/services/settings/settings.service.ts b/teammapper-frontend/src/app/core/services/settings/settings.service.ts index cfd300574..102c6915a 100644 --- a/teammapper-frontend/src/app/core/services/settings/settings.service.ts +++ b/teammapper-frontend/src/app/core/services/settings/settings.service.ts @@ -2,10 +2,13 @@ import { Injectable, inject } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { CachedAdminMapEntry } from 'src/app/shared/models/cached-map.model'; -import { Settings } from '../../../shared/models/settings.model'; +import { + Settings, + SystemSettings, + UserSettings, +} from '../../../shared/models/settings.model'; import { API_URL, HttpService } from '../../http/http.service'; import { STORAGE_KEYS, StorageService } from '../storage/storage.service'; -import { environment } from 'src/environments/environment'; @Injectable({ providedIn: 'root', @@ -27,15 +30,17 @@ export class SettingsService { 'pt-br', ]; - public settings: Observable; - private settingsSubject: BehaviorSubject; + public userSettings: Observable; + private userSettingsSubject: BehaviorSubject; + private systemSettingsSubject: BehaviorSubject; private readonly editModeSubject: BehaviorSubject; constructor() { // Initialization of the behavior subjects. - this.settingsSubject = new BehaviorSubject(null); + this.userSettingsSubject = new BehaviorSubject(null); + this.systemSettingsSubject = new BehaviorSubject(null); this.editModeSubject = new BehaviorSubject(null); - this.settings = this.settingsSubject.asObservable(); + this.userSettings = this.userSettingsSubject.asObservable(); } /** @@ -43,26 +48,27 @@ export class SettingsService { */ public async init() { const defaultSettings: Settings = await this.getDefaultSettings(); - defaultSettings.general.language = + defaultSettings.userSettings.general.language = this.translateService.getBrowserLang() ?? - defaultSettings.general.language; - const loadedSettings: Settings = await this.storageService.get( + defaultSettings.userSettings.general.language; + const loadedSettings: UserSettings = await this.storageService.get( STORAGE_KEYS.SETTINGS ); - const settings = loadedSettings || defaultSettings; + const userSettings = loadedSettings || defaultSettings.userSettings; // Save the default settings. - await this.storageService.set(STORAGE_KEYS.SETTINGS, settings); - this.settingsSubject.next(settings); + await this.storageService.set(STORAGE_KEYS.SETTINGS, userSettings); + this.userSettingsSubject.next(userSettings); + this.systemSettingsSubject.next(defaultSettings.systemSettings); return true; } /** * Update the settings in the storage. */ - public async updateCachedSettings(settings: Settings): Promise { + public async updateCachedSettings(settings: UserSettings): Promise { await this.storageService.set(STORAGE_KEYS.SETTINGS, settings); - this.settingsSubject.next(settings); + this.userSettingsSubject.next(settings); } public async getCachedAdminMapEntries(): Promise { @@ -88,8 +94,12 @@ export class SettingsService { /** * Return the current settings. */ - public getCachedSettings(): Settings | null { - return this.settingsSubject.getValue(); + public getCachedUserSettings(): UserSettings | null { + return this.userSettingsSubject.getValue(); + } + + public getCachedSystemSettings(): SystemSettings | null { + return this.systemSettingsSubject.getValue(); } public getEditModeObservable(): Observable { @@ -104,11 +114,8 @@ export class SettingsService { * Return the default settings. */ public async getDefaultSettings(): Promise { - const response = await this.httpService.get( - API_URL.LOCAL_ASSETS, - environment.settingsFilePath ?? 'settings.json' - ); - return response.json(); + const response = await this.httpService.get(API_URL.ROOT, '/settings'); + return await response.json(); } } diff --git a/teammapper-frontend/src/app/core/services/toast/toast.service.spec.ts b/teammapper-frontend/src/app/core/services/toast/toast.service.spec.ts new file mode 100644 index 000000000..b94fdd37c --- /dev/null +++ b/teammapper-frontend/src/app/core/services/toast/toast.service.spec.ts @@ -0,0 +1,254 @@ +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { ToastrService } from 'ngx-toastr'; +import { ToastService } from './toast.service'; + +describe('ToastService', () => { + let service: ToastService; + let toastrSpy: jest.Mocked; + + beforeEach(() => { + const spy = { + error: jest.fn(), + warning: jest.fn(), + info: jest.fn(), + success: jest.fn(), + } as unknown as jest.Mocked; + + TestBed.configureTestingModule({ + providers: [ToastService, { provide: ToastrService, useValue: spy }], + }); + + service = TestBed.inject(ToastService); + toastrSpy = TestBed.inject( + ToastrService + ) as unknown as jest.Mocked; + }); + + describe('showValidationCorrection()', () => { + it('should display warning toast with correct message', fakeAsync(() => { + service.showValidationCorrection('Test Node', 'parent was reset to root'); + + // Wait for throttle time (500ms) + tick(500); + + expect(toastrSpy.warning).toHaveBeenCalledWith( + 'Node "Test Node" was auto-corrected: parent was reset to root', + '', + expect.objectContaining({ + timeOut: 4000, + }) + ); + })); + + it('should display message without node name if not provided', fakeAsync(() => { + service.showValidationCorrection('', 'parent was reset to root'); + + tick(500); + + expect(toastrSpy.warning).toHaveBeenCalledWith( + 'Node was auto-corrected: parent was reset to root', + '', + expect.anything() + ); + })); + + it('should include correction details in message', fakeAsync(() => { + service.showValidationCorrection( + 'Meeting Notes', + 'invalid reference removed' + ); + + tick(500); + + const call = + toastrSpy.warning.mock.calls[toastrSpy.warning.mock.calls.length - 1]; + expect(call[0]).toContain('invalid reference removed'); + })); + + it('should use 4 second duration', fakeAsync(() => { + service.showValidationCorrection('Test', 'corrected'); + + tick(500); + + const call = + toastrSpy.warning.mock.calls[toastrSpy.warning.mock.calls.length - 1]; + expect(call[2]).toEqual({ timeOut: 4000 }); + })); + }); + + describe('throttling', () => { + it('should prevent toast spam by showing first message only', fakeAsync(() => { + // Rapid fire toasts + service.showValidationCorrection('Node 1', 'correction 1'); + tick(100); + service.showValidationCorrection('Node 2', 'correction 2'); + tick(100); + service.showValidationCorrection('Node 3', 'correction 3'); + + // Wait for throttle time + tick(500); + + // Only the FIRST toast should be shown (throttle behavior, not debounce) + expect(toastrSpy.warning).toHaveBeenCalledTimes(1); + expect(toastrSpy.warning).toHaveBeenCalledWith( + expect.stringContaining('Node 1'), + expect.anything(), + expect.anything() + ); + })); + + it('should show multiple toasts if separated by throttle time', fakeAsync(() => { + service.showValidationCorrection('Node 1', 'correction 1'); + tick(500); + + service.showValidationCorrection('Node 2', 'correction 2'); + tick(500); + + expect(toastrSpy.warning).toHaveBeenCalledTimes(2); + })); + + it('should throttle all toast types', fakeAsync(() => { + service.showInfo('Info message'); + tick(100); + service.showWarning('Warning message'); + tick(100); + service.showError('Error message'); + + tick(500); + + // Only first one should be shown (throttle shows first, not last) + expect(toastrSpy.info).toHaveBeenCalledTimes(1); + expect(toastrSpy.warning).toHaveBeenCalledTimes(0); + expect(toastrSpy.error).toHaveBeenCalledTimes(0); + expect(toastrSpy.info).toHaveBeenCalledWith( + 'Info message', + expect.anything(), + expect.anything() + ); + })); + }); + + describe('showInfo()', () => { + it('should display info toast with default duration', fakeAsync(() => { + service.showInfo('Information message'); + + tick(500); + + expect(toastrSpy.info).toHaveBeenCalledWith( + 'Information message', + '', + expect.objectContaining({ + timeOut: 4000, + }) + ); + })); + }); + + describe('showWarning()', () => { + it('should display warning toast with default duration', fakeAsync(() => { + service.showWarning('Warning message'); + + tick(500); + + expect(toastrSpy.warning).toHaveBeenCalledWith( + 'Warning message', + '', + expect.objectContaining({ + timeOut: 4000, + }) + ); + })); + }); + + describe('showError()', () => { + it('should display error toast with default duration', fakeAsync(() => { + service.showError('Error message'); + + tick(500); + + expect(toastrSpy.error).toHaveBeenCalledWith( + 'Error message', + '', + expect.objectContaining({ + timeOut: 4000, + }) + ); + })); + }); + + describe('toast queueing', () => { + it('should display toast immediately with throttle leading', fakeAsync(() => { + service.showValidationCorrection('Node 1', 'correction'); + + // With leading: true, toast is displayed immediately + tick(0); + expect(toastrSpy.warning).toHaveBeenCalledTimes(1); + + // After throttle time passes, can show another toast + tick(500); + service.showValidationCorrection('Node 2', 'correction 2'); + tick(0); + expect(toastrSpy.warning).toHaveBeenCalledTimes(2); + })); + + it('should handle multiple messages in quick succession', fakeAsync(() => { + // Simulate rapid operations triggering toasts + for (let i = 0; i < 10; i++) { + service.showValidationCorrection(`Node ${i}`, 'correction'); + tick(50); + } + + tick(500); + + // Only one toast should be shown (the first one due to throttling) + expect(toastrSpy.warning).toHaveBeenCalledTimes(1); + expect(toastrSpy.warning).toHaveBeenCalledWith( + expect.stringContaining('Node 0'), + expect.anything(), + expect.anything() + ); + })); + }); + + describe('toast types', () => { + it('should call toastr.warning for validation corrections', fakeAsync(() => { + service.showValidationCorrection('Test', 'correction'); + tick(500); + + expect(toastrSpy.warning).toHaveBeenCalled(); + expect(toastrSpy.error).not.toHaveBeenCalled(); + expect(toastrSpy.info).not.toHaveBeenCalled(); + expect(toastrSpy.success).not.toHaveBeenCalled(); + })); + + it('should call toastr.info for info messages', fakeAsync(() => { + service.showInfo('Test info'); + tick(500); + + expect(toastrSpy.info).toHaveBeenCalled(); + expect(toastrSpy.error).not.toHaveBeenCalled(); + expect(toastrSpy.warning).not.toHaveBeenCalled(); + expect(toastrSpy.success).not.toHaveBeenCalled(); + })); + + it('should call toastr.warning for warnings', fakeAsync(() => { + service.showWarning('Test warning'); + tick(500); + + expect(toastrSpy.warning).toHaveBeenCalled(); + expect(toastrSpy.error).not.toHaveBeenCalled(); + expect(toastrSpy.info).not.toHaveBeenCalled(); + expect(toastrSpy.success).not.toHaveBeenCalled(); + })); + + it('should call toastr.error for errors', fakeAsync(() => { + service.showError('Test error'); + tick(500); + + expect(toastrSpy.error).toHaveBeenCalled(); + expect(toastrSpy.warning).not.toHaveBeenCalled(); + expect(toastrSpy.info).not.toHaveBeenCalled(); + expect(toastrSpy.success).not.toHaveBeenCalled(); + })); + }); +}); diff --git a/teammapper-frontend/src/app/core/services/toast/toast.service.ts b/teammapper-frontend/src/app/core/services/toast/toast.service.ts new file mode 100644 index 000000000..d11c7cce5 --- /dev/null +++ b/teammapper-frontend/src/app/core/services/toast/toast.service.ts @@ -0,0 +1,104 @@ +import { Injectable, inject } from '@angular/core'; +import { ToastrService } from 'ngx-toastr'; +import { Subject } from 'rxjs'; +import { throttleTime } from 'rxjs/operators'; + +/** + * Service for displaying toast notifications using ngx-toastr + * Includes throttling to prevent toast spam + */ +@Injectable({ providedIn: 'root' }) +export class ToastService { + private readonly THROTTLE_TIME_MS = 500; + private readonly TOAST_DURATION_MS = 4000; + + private toastr = inject(ToastrService); + private toastQueue = new Subject(); + + constructor() { + // Setup throttled toast display - shows first message, ignores subsequent ones + this.toastQueue + .pipe( + throttleTime(this.THROTTLE_TIME_MS, undefined, { + leading: true, + trailing: false, + }) + ) + .subscribe(message => { + this.displayToast(message); + }); + } + + /** + * Display a validation correction notification + * @param nodeName Name of the node that was corrected + * @param correctionDetails Details about what was corrected + */ + showValidationCorrection(nodeName: string, correctionDetails: string): void { + const message = nodeName + ? `Node "${nodeName}" was auto-corrected: ${correctionDetails}` + : `Node was auto-corrected: ${correctionDetails}`; + + this.queueToast({ message, type: 'warning' }); + } + + /** + * Display a general info toast + * @param message Message to display + */ + showInfo(message: string): void { + this.queueToast({ message, type: 'info' }); + } + + /** + * Display a warning toast + * @param message Message to display + */ + showWarning(message: string): void { + this.queueToast({ message, type: 'warning' }); + } + + /** + * Display an error toast + * @param message Message to display + */ + showError(message: string): void { + this.queueToast({ message, type: 'error' }); + } + + /** + * Queue a toast message (will be throttled) + * @param toast Toast message to queue + */ + private queueToast(toast: ToastMessage): void { + this.toastQueue.next(toast); + } + + /** + * Display a toast immediately (after throttle) + * @param toast Toast message to display + */ + private displayToast(toast: ToastMessage): void { + const options = { timeOut: this.TOAST_DURATION_MS }; + + switch (toast.type) { + case 'error': + this.toastr.error(toast.message, '', options); + break; + case 'warning': + this.toastr.warning(toast.message, '', options); + break; + case 'info': + this.toastr.info(toast.message, '', options); + break; + case 'success': + this.toastr.success(toast.message, '', options); + break; + } + } +} + +interface ToastMessage { + message: string; + type: 'error' | 'warning' | 'info' | 'success'; +} diff --git a/teammapper-frontend/src/app/core/services/utils/utils.service.ts b/teammapper-frontend/src/app/core/services/utils/utils.service.ts index ff339f1dc..9417a19c9 100644 --- a/teammapper-frontend/src/app/core/services/utils/utils.service.ts +++ b/teammapper-frontend/src/app/core/services/utils/utils.service.ts @@ -1,5 +1,5 @@ import { Injectable, inject } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable, firstValueFrom } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; @Injectable({ @@ -14,7 +14,9 @@ export class UtilsService { public static get = (obj: any, path: string[]) => path.reduce( (nestedObj, currentPath) => - nestedObj && nestedObj[currentPath] ? nestedObj[currentPath] : null, + nestedObj != null && currentPath in nestedObj + ? nestedObj[currentPath] + : null, obj ); @@ -135,7 +137,7 @@ export class UtilsService { * Return a translated string with given message and values. */ public translate(message: string, values?: any): Promise { - return this.translateService.get(message, values).toPromise(); + return firstValueFrom(this.translateService.get(message, values)); } /** diff --git a/teammapper-frontend/src/app/modules/about/components/footer/footer.component.spec.ts b/teammapper-frontend/src/app/modules/about/components/footer/footer.component.spec.ts index e765daf72..f10859993 100644 --- a/teammapper-frontend/src/app/modules/about/components/footer/footer.component.spec.ts +++ b/teammapper-frontend/src/app/modules/about/components/footer/footer.component.spec.ts @@ -26,7 +26,7 @@ describe('FooterComponent', () => { beforeEach(async () => { mockSettingsService = { - getCachedSettings: jest.fn().mockReturnValue(mockSettings), + getCachedUserSettings: jest.fn().mockReturnValue(mockSettings), updateCachedSettings: jest.fn().mockResolvedValue(undefined), }; mockTranslateService = { @@ -65,7 +65,7 @@ describe('FooterComponent', () => { }); it('should initialize with correct settings and languages', () => { - expect(mockSettingsService.getCachedSettings).toHaveBeenCalled(); + expect(mockSettingsService.getCachedUserSettings).toHaveBeenCalled(); expect(component.languages).toEqual([ 'en', 'fr', diff --git a/teammapper-frontend/src/app/modules/about/components/footer/footer.component.ts b/teammapper-frontend/src/app/modules/about/components/footer/footer.component.ts index b466db4e1..7ddc157b7 100644 --- a/teammapper-frontend/src/app/modules/about/components/footer/footer.component.ts +++ b/teammapper-frontend/src/app/modules/about/components/footer/footer.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, inject } from '@angular/core'; import { SettingsService } from '../../../../core/services/settings/settings.service'; import { TranslateService, TranslatePipe } from '@ngx-translate/core'; -import { Settings } from '../../../../shared/models/settings.model'; +import { UserSettings } from '../../../../shared/models/settings.model'; import { MatSelect, MatOption } from '@angular/material/select'; import { NgFor } from '@angular/common'; @@ -15,13 +15,13 @@ export class FooterComponent implements OnInit { private settingsService = inject(SettingsService); private translateService = inject(TranslateService); - public settings: Settings; + public settings: UserSettings; public languages: string[]; public currentYear: string; public ngOnInit() { - this.settings = this.settingsService.getCachedSettings(); + this.settings = this.settingsService.getCachedUserSettings(); this.languages = SettingsService.LANGUAGES; this.currentYear = new Date().getFullYear().toString(); diff --git a/teammapper-frontend/src/app/modules/about/pages/about/about.component.html b/teammapper-frontend/src/app/modules/about/pages/about/about.component.html index 0d3c2235a..0b1208d59 100644 --- a/teammapper-frontend/src/app/modules/about/pages/about/about.component.html +++ b/teammapper-frontend/src/app/modules/about/pages/about/about.component.html @@ -62,5 +62,11 @@

+
+
+ +
+
+ diff --git a/teammapper-frontend/src/app/modules/about/pages/about/about.component.ts b/teammapper-frontend/src/app/modules/about/pages/about/about.component.ts index c79632880..f3775a5ea 100644 --- a/teammapper-frontend/src/app/modules/about/pages/about/about.component.ts +++ b/teammapper-frontend/src/app/modules/about/pages/about/about.component.ts @@ -20,12 +20,14 @@ import { } from '@angular/material/card'; import { FooterComponent } from '../../components/footer/footer.component'; import { TranslatePipe } from '@ngx-translate/core'; +import { MindmapsOverview } from 'src/app/shared/components/mindmaps-overview/mindmaps-overview.component'; @Component({ selector: 'teammapper-about', templateUrl: './about.component.html', styleUrls: ['./about.component.scss'], imports: [ + MindmapsOverview, HeaderComponent, JumbotronComponent, FaIconComponent, diff --git a/teammapper-frontend/src/app/modules/application/components/dialog-about/dialog-about.component.ts b/teammapper-frontend/src/app/modules/application/components/dialog-about/dialog-about.component.ts index 9d3103215..80647819c 100644 --- a/teammapper-frontend/src/app/modules/application/components/dialog-about/dialog-about.component.ts +++ b/teammapper-frontend/src/app/modules/application/components/dialog-about/dialog-about.component.ts @@ -5,7 +5,6 @@ import { MapProperties } from '@mmp/map/types'; import { SettingsService } from 'src/app/core/services/settings/settings.service'; import { StorageService } from 'src/app/core/services/storage/storage.service'; import { MapSyncService } from 'src/app/core/services/map-sync/map-sync.service'; -import { environment } from 'src/environments/environment'; import { Router } from '@angular/router'; import { MatDialogRef, @@ -46,14 +45,15 @@ export class DialogAboutComponent { private router = inject(Router); public faGithub = faGithub; - public version: string; - public applicationName: string; + public version = ''; + public applicationName = 'TeamMapper'; public map: MapProperties; public mapAdminId: Promise; constructor() { - this.version = environment.version; - this.applicationName = environment.name; + const settings = this.settingsService.getCachedSystemSettings(); + this.version = settings.info?.version || this.version; + this.applicationName = settings.info?.name || this.applicationName; this.map = this.mapSyncService.getAttachedMap().cachedMap; this.mapAdminId = this.getMapAdminId(); } @@ -76,7 +76,7 @@ export class DialogAboutComponent { } language(): string { - return this.settingsService.getCachedSettings().general.language; + return this.settingsService.getCachedUserSettings().general.language; } async getMapAdminId(): Promise { diff --git a/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.html b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.html new file mode 100644 index 000000000..74e34ddb0 --- /dev/null +++ b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.html @@ -0,0 +1,19 @@ +

+ warning + {{ 'MODALS.CRITICAL_ERROR.TITLE' | translate }} +

+ + +

{{ data.message }}

+

{{ 'MODALS.CRITICAL_ERROR.WARNING' | translate }}

+
+ + + + diff --git a/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.scss b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.scss new file mode 100644 index 000000000..e63694832 --- /dev/null +++ b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.scss @@ -0,0 +1,39 @@ +.error-title { + display: flex; + align-items: center; + gap: 0.5rem; + color: var(--mat-dialog-headline-color, rgba(0, 0, 0, 0.87)); +} + +.error-icon { + color: #f44336; // Material red-500 + font-size: 28px; + width: 28px; + height: 28px; +} + +.error-message { + font-size: 16px; + line-height: 1.5; + margin-bottom: 1rem; + color: var(--mat-dialog-content-color, rgba(0, 0, 0, 0.87)); +} + +.warning-text { + font-size: 14px; + line-height: 1.5; + color: var(--mat-dialog-content-color, rgba(0, 0, 0, 0.6)); + font-style: italic; +} + +mat-dialog-content { + padding: 1rem 1.5rem; +} + +mat-dialog-actions { + padding: 0.5rem 1.5rem 1rem; +} + +.reload-button { + min-width: 120px; +} diff --git a/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.spec.ts b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.spec.ts new file mode 100644 index 000000000..be58da596 --- /dev/null +++ b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.spec.ts @@ -0,0 +1,76 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { + MatDialogRef, + MAT_DIALOG_DATA, + MatDialogModule, +} from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { + DialogCriticalErrorComponent, + CriticalErrorData, +} from './dialog-critical-error.component'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TranslateModule } from '@ngx-translate/core'; + +describe('DialogCriticalErrorComponent', () => { + let component: DialogCriticalErrorComponent; + let fixture: ComponentFixture; + let mockDialogRef: jest.Mocked>; + let mockErrorData: CriticalErrorData; + + beforeEach(async () => { + mockDialogRef = { + disableClose: false, + close: jest.fn(), + } as unknown as jest.Mocked>; + + mockErrorData = { + code: 'SERVER_ERROR', + message: 'We lost connection to the server. Please reload the page.', + }; + + await TestBed.configureTestingModule({ + imports: [ + DialogCriticalErrorComponent, + MatDialogModule, + MatIconModule, + MatButtonModule, + NoopAnimationsModule, + TranslateModule.forRoot(), + ], + providers: [ + { provide: MatDialogRef, useValue: mockDialogRef }, + { provide: MAT_DIALOG_DATA, useValue: mockErrorData }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(DialogCriticalErrorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create and display error message', () => { + expect(component).toBeTruthy(); + + const contentElement = + fixture.nativeElement.querySelector('mat-dialog-content'); + expect(contentElement.textContent).toContain(mockErrorData.message); + }); + + it('should be a blocking dialog that cannot be dismissed', () => { + expect(component.dialogRef.disableClose).toBe(true); + }); + + it('should reload page when button is clicked', () => { + const reloadMock = jest.fn(); + Object.defineProperty(window, 'location', { + value: { reload: reloadMock }, + writable: true, + }); + + component.reloadPage(); + + expect(reloadMock).toHaveBeenCalled(); + }); +}); diff --git a/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.ts b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.ts new file mode 100644 index 000000000..97da1e55c --- /dev/null +++ b/teammapper-frontend/src/app/modules/application/components/dialog-critical-error/dialog-critical-error.component.ts @@ -0,0 +1,55 @@ +import { Component, inject } from '@angular/core'; +import { + MAT_DIALOG_DATA, + MatDialogRef, + MatDialogTitle, + MatDialogContent, + MatDialogActions, +} from '@angular/material/dialog'; +import { MatButton } from '@angular/material/button'; +import { MatIcon } from '@angular/material/icon'; +import { TranslatePipe } from '@ngx-translate/core'; + +/** + * Data passed to critical error dialog component + */ +export interface CriticalErrorData { + code: string; + message: string; +} + +/** + * Critical Error Dialog Component + * Displays a blocking modal for critical errors that require page reload + * Cannot be dismissed by clicking outside or pressing escape + */ +@Component({ + selector: 'teammapper-dialog-critical-error', + templateUrl: './dialog-critical-error.component.html', + styleUrls: ['./dialog-critical-error.component.scss'], + imports: [ + MatDialogTitle, + MatDialogContent, + MatDialogActions, + MatButton, + MatIcon, + TranslatePipe, + ], +}) +export class DialogCriticalErrorComponent { + public dialogRef = + inject>(MatDialogRef); + public data = inject(MAT_DIALOG_DATA); + + constructor() { + // Prevent closing dialog by clicking outside or pressing escape + this.dialogRef.disableClose = true; + } + + /** + * Reload the page to recover from critical error + */ + reloadPage(): void { + window.location.reload(); + } +} diff --git a/teammapper-frontend/src/app/modules/application/components/dialog-import-ai/dialog-import-ai.component.ts b/teammapper-frontend/src/app/modules/application/components/dialog-import-ai/dialog-import-ai.component.ts index ee11b7884..43a0b663e 100644 --- a/teammapper-frontend/src/app/modules/application/components/dialog-import-ai/dialog-import-ai.component.ts +++ b/teammapper-frontend/src/app/modules/application/components/dialog-import-ai/dialog-import-ai.component.ts @@ -74,7 +74,8 @@ export class DialogImportAiComponent { JSON.stringify({ mindmapDescription: this.mindmapDescription, language: - this.settingsService.getCachedSettings().general.language ?? 'en', + this.settingsService.getCachedUserSettings().general.language ?? + 'en', }) ); diff --git a/teammapper-frontend/src/app/modules/application/components/dialog-import-mermaid/dialog-import-mermaid.component.ts b/teammapper-frontend/src/app/modules/application/components/dialog-import-mermaid/dialog-import-mermaid.component.ts index 79ae251be..43f192f03 100644 --- a/teammapper-frontend/src/app/modules/application/components/dialog-import-mermaid/dialog-import-mermaid.component.ts +++ b/teammapper-frontend/src/app/modules/application/components/dialog-import-mermaid/dialog-import-mermaid.component.ts @@ -25,7 +25,6 @@ import { NgIf } from '@angular/common'; import { SettingsService } from 'src/app/core/services/settings/settings.service'; import { ToastrService } from 'ngx-toastr'; import { UtilsService } from 'src/app/core/services/utils/utils.service'; -import { environment } from 'src/environments/environment'; @Component({ selector: 'teammapper-dialog-import-mermaid', @@ -62,7 +61,8 @@ export class DialogImportMermaidComponent { public mermaidInput = ''; public mindmapDescription = ''; - public featureFlagAI: boolean = environment.featureFlagAI; + public featureFlagAI: boolean = + this.settingsService.getCachedSystemSettings().featureFlags.ai; async createMermaidMindmapFromServer(): Promise { this.toastService.info( @@ -74,7 +74,7 @@ export class DialogImportMermaidComponent { JSON.stringify({ mindmapDescription: this.mindmapDescription, language: - this.settingsService.getCachedSettings().general.language ?? 'en', + this.settingsService.getCachedUserSettings().general.language ?? 'en', }) ); if (response.status === 201) { diff --git a/teammapper-frontend/src/app/modules/application/components/map/map.component.ts b/teammapper-frontend/src/app/modules/application/components/map/map.component.ts index 8573eaf5f..b2c98bd4c 100644 --- a/teammapper-frontend/src/app/modules/application/components/map/map.component.ts +++ b/teammapper-frontend/src/app/modules/application/components/map/map.component.ts @@ -28,7 +28,7 @@ export class MapComponent implements AfterViewInit, OnDestroy { private mapSyncServiceSubscription: Subscription; public async ngAfterViewInit() { - const settings = this.settingsService.getCachedSettings(); + const settings = this.settingsService.getCachedUserSettings(); this.mapSyncServiceSubscription = this.mapSyncService .getAttachedMapObservable() diff --git a/teammapper-frontend/src/app/modules/application/components/toolbar/toolbar.component.ts b/teammapper-frontend/src/app/modules/application/components/toolbar/toolbar.component.ts index 86df227be..1de4bf402 100644 --- a/teammapper-frontend/src/app/modules/application/components/toolbar/toolbar.component.ts +++ b/teammapper-frontend/src/app/modules/application/components/toolbar/toolbar.component.ts @@ -3,13 +3,13 @@ import { ExportNodeProperties } from '@mmp/map/types'; import { TranslateService, TranslatePipe } from '@ngx-translate/core'; import { DialogService } from 'src/app/core/services/dialog/dialog.service'; import { MmpService } from 'src/app/core/services/mmp/mmp.service'; -import { environment } from 'src/environments/environment'; import { MatToolbar } from '@angular/material/toolbar'; import { RouterLink } from '@angular/router'; import { MatIconButton } from '@angular/material/button'; import { MatIcon } from '@angular/material/icon'; import { MatMenuTrigger, MatMenu, MatMenuItem } from '@angular/material/menu'; import { NgClass, NgIf } from '@angular/common'; +import { SettingsService } from 'src/app/core/services/settings/settings.service'; @Component({ selector: 'teammapper-toolbar', @@ -35,8 +35,15 @@ export class ToolbarComponent { @Input() public node: ExportNodeProperties; @Input() public editDisabled: boolean; - public featureFlagPictograms: boolean = environment.featureFlagPictograms; - public featureFlagAI: boolean = environment.featureFlagAI; + public featureFlagPictograms: boolean; + + private settingsService = inject(SettingsService); + public featureFlagAI: boolean; + + constructor() { + this.featureFlagPictograms = + this.settingsService.getCachedSystemSettings()?.featureFlags?.pictograms; + } public async exportMap(format: string) { const result = await this.mmpService.exportMap(format); diff --git a/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.html b/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.html index 3d16e1947..de629e9c8 100644 --- a/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.html +++ b/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.html @@ -155,36 +155,8 @@

{{ 'PAGES.SETTINGS.TITLE' | translate }}

-
- - - {{ - 'PAGES.SETTINGS.MAP_LIST' | translate - }} - -
- - - - - {{ - getMapTitle(cachedMapEntry) - }} - - - {{ 'PAGES.SETTINGS.TTL' | translate }}: - {{ - cachedMapEntry.cachedAdminMapValue.ttl - | date: 'yyyy-MM-dd' - }} - - - -
-
+
- + \ No newline at end of file diff --git a/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.scss b/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.scss index 40be5197e..27a992da4 100644 --- a/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.scss +++ b/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.scss @@ -61,6 +61,6 @@ div.settings { } div.content.container { - padding-bottom: 20px; // or whatever value you prefer + padding-bottom: 20px; } } diff --git a/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.ts b/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.ts index 08ed47b43..447aa5e99 100644 --- a/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.ts +++ b/teammapper-frontend/src/app/modules/application/pages/settings/settings.component.ts @@ -1,16 +1,12 @@ -import { Component, OnInit, inject } from '@angular/core'; -import { Settings } from '../../../../shared/models/settings.model'; +import { Component, inject } from '@angular/core'; +import { UserSettings } from '../../../../shared/models/settings.model'; import { SettingsService } from '../../../../core/services/settings/settings.service'; import { MmpService } from '../../../../core/services/mmp/mmp.service'; import { TranslateService, TranslatePipe } from '@ngx-translate/core'; -import { Location, NgFor, NgIf, AsyncPipe, DatePipe } from '@angular/common'; -import { Router } from '@angular/router'; +import { Location, NgFor, NgIf, AsyncPipe } from '@angular/common'; import { Observable } from 'rxjs'; import { MapSyncService } from 'src/app/core/services/map-sync/map-sync.service'; -import { - CachedAdminMapEntry, - CachedMapOptions, -} from 'src/app/shared/models/cached-map.model'; +import { CachedMapOptions } from 'src/app/shared/models/cached-map.model'; import { MatToolbar } from '@angular/material/toolbar'; import { MatDialogTitle } from '@angular/material/dialog'; import { MatIconButton } from '@angular/material/button'; @@ -27,15 +23,15 @@ import { MatSelect, MatOption } from '@angular/material/select'; import { MatSlideToggle } from '@angular/material/slide-toggle'; import { FormsModule } from '@angular/forms'; import { MatInput } from '@angular/material/input'; -import { MatList, MatListItem } from '@angular/material/list'; -import { MatLine } from '@angular/material/core'; import { InverseBoolPipe } from '../../../../shared/pipes/inverse-bool.pipe'; +import { MindmapsOverview } from 'src/app/shared/components/mindmaps-overview/mindmaps-overview.component'; @Component({ selector: 'teammapper-settings', templateUrl: './settings.component.html', styleUrls: ['./settings.component.scss'], imports: [ + MindmapsOverview, MatToolbar, MatDialogTitle, MatIconButton, @@ -54,46 +50,34 @@ import { InverseBoolPipe } from '../../../../shared/pipes/inverse-bool.pipe'; MatSlideToggle, FormsModule, MatInput, - MatList, - MatListItem, - MatLine, AsyncPipe, - DatePipe, TranslatePipe, InverseBoolPipe, ], }) -export class SettingsComponent implements OnInit { +export class SettingsComponent { private settingsService = inject(SettingsService); private mmpService = inject(MmpService); private mapSyncService = inject(MapSyncService); private translateService = inject(TranslateService); - private router = inject(Router); private location = inject(Location); public readonly languages: string[]; - public settings: Settings; + public settings: UserSettings; public mapOptions: CachedMapOptions; public editMode: Observable; - public cachedAdminMapEntries: CachedAdminMapEntry[]; constructor() { this.languages = SettingsService.LANGUAGES; - this.settings = this.settingsService.getCachedSettings(); + this.settings = this.settingsService.getCachedUserSettings(); this.mapOptions = this.mmpService.getAdditionalMapOptions(); this.editMode = this.settingsService.getEditModeObservable(); - this.cachedAdminMapEntries = []; } public async updateGeneralMapOptions() { await this.settingsService.updateCachedSettings(this.settings); } - public async ngOnInit() { - this.cachedAdminMapEntries = - await this.settingsService.getCachedAdminMapEntries(); - } - public async updateMapOptions() { await this.validateMapOptionsInput(); this.mapSyncService.updateMapOptions(this.mapOptions); @@ -109,21 +93,10 @@ export class SettingsComponent implements OnInit { this.location.back(); } - public getMapUrl(entry: CachedAdminMapEntry): string { - return this.router - .createUrlTree([`/map/${entry.id}`], { - fragment: entry.cachedAdminMapValue.modificationSecret, - }) - .toString(); - } - - public getMapTitle(entry: CachedAdminMapEntry): string { - return entry.cachedAdminMapValue.rootName || entry.id; - } - private async validateMapOptionsInput() { - const defaultSettings: Settings = - await this.settingsService.getDefaultSettings(); + const defaultSettings: UserSettings = ( + await this.settingsService.getDefaultSettings() + ).userSettings; if ( this.mapOptions.fontIncrement > this.mapOptions.fontMaxSize || this.mapOptions.fontIncrement < 1 diff --git a/teammapper-frontend/src/app/root.component.ts b/teammapper-frontend/src/app/root.component.ts index d1fa002f4..125051ba7 100644 --- a/teammapper-frontend/src/app/root.component.ts +++ b/teammapper-frontend/src/app/root.component.ts @@ -21,7 +21,7 @@ export class RootComponent implements OnInit { public tapCounter = 0; public async ngOnInit() { - const settings = this.settingsService.getCachedSettings(); + const settings = this.settingsService.getCachedUserSettings(); await this.initTranslations(settings.general.language); diff --git a/teammapper-frontend/src/app/shared/components/.gitkeep b/teammapper-frontend/src/app/shared/components/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.html b/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.html new file mode 100644 index 000000000..42fd4e592 --- /dev/null +++ b/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.html @@ -0,0 +1,56 @@ +
+ + + {{ + 'PAGES.SETTINGS.OWNED_MAPS' | translate + }} + +
+ + + + + {{ + getMapTitle(ownedEntry) + }} + + + {{ 'PAGES.SETTINGS.TTL' | translate }}: + {{ + ownedEntry.cachedAdminMapValue.ttl + | date: 'yyyy-MM-dd' + }} + + + + +
+ + + {{ + 'PAGES.SETTINGS.LAST_MAPS' | translate + }} + +
+ + + + + {{ + getMapTitle(cachedMapEntry) + }} + + + {{ 'PAGES.SETTINGS.TTL' | translate }}: + {{ + cachedMapEntry.cachedAdminMapValue.ttl + | date: 'yyyy-MM-dd' + }} + + + + +
+
\ No newline at end of file diff --git a/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.scss b/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.scss new file mode 100644 index 000000000..c7f30fed9 --- /dev/null +++ b/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.scss @@ -0,0 +1,17 @@ +div.content { + mat-card { + margin-bottom: 20px; + + hr { + margin-top: 0; + margin-bottom: 20px; + border: 0; + height: 1px; + background-color: lightgray; + } + } + + mat-card:last-child { + margin-bottom: 0; + } +} \ No newline at end of file diff --git a/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.ts b/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.ts new file mode 100644 index 000000000..ea1e9e280 --- /dev/null +++ b/teammapper-frontend/src/app/shared/components/mindmaps-overview/mindmaps-overview.component.ts @@ -0,0 +1,64 @@ +import { Component, inject, OnInit } from '@angular/core'; +import { CachedAdminMapEntry } from '../../models/cached-map.model'; +import { SettingsService } from 'src/app/core/services/settings/settings.service'; +import { MapSyncService } from 'src/app/core/services/map-sync/map-sync.service'; +import { Router } from '@angular/router'; +import { + MatCard, + MatCardContent, + MatCardHeader, + MatCardTitle, +} from '@angular/material/card'; +import { MatList, MatListItem } from '@angular/material/list'; +import { MatLine } from '@angular/material/core'; +import { CommonModule, DatePipe } from '@angular/common'; +import { TranslatePipe } from '@ngx-translate/core'; + +@Component({ + selector: 'teammapper-mindmaps-overview', + templateUrl: './mindmaps-overview.component.html', + styleUrl: './mindmaps-overview.component.scss', + imports: [ + MatCard, + MatCardHeader, + MatCardContent, + MatCardTitle, + MatList, + MatListItem, + MatLine, + DatePipe, + TranslatePipe, + CommonModule, + ], +}) +export class MindmapsOverview implements OnInit { + private settingsService = inject(SettingsService); + private mapSyncService = inject(MapSyncService); + private router = inject(Router); + + public cachedAdminMapEntries: CachedAdminMapEntry[]; + public ownedEntries: CachedAdminMapEntry[]; + + constructor() { + this.cachedAdminMapEntries = []; + this.ownedEntries = []; + } + + public async ngOnInit() { + this.cachedAdminMapEntries = + await this.settingsService.getCachedAdminMapEntries(); + this.ownedEntries = await this.mapSyncService.fetchUserMapsFromServer(); + } + + public getMapUrl(entry: CachedAdminMapEntry): string { + return this.router + .createUrlTree([`/map/${entry.id}`], { + fragment: entry.cachedAdminMapValue.modificationSecret, + }) + .toString(); + } + + public getMapTitle(entry: CachedAdminMapEntry): string { + return entry.cachedAdminMapValue.rootName || entry.id; + } +} diff --git a/teammapper-frontend/src/app/shared/models/settings.model.ts b/teammapper-frontend/src/app/shared/models/settings.model.ts index 89567560e..174841fb6 100644 --- a/teammapper-frontend/src/app/shared/models/settings.model.ts +++ b/teammapper-frontend/src/app/shared/models/settings.model.ts @@ -12,6 +12,17 @@ export interface MmpOptions extends OptionParameters { } export interface Settings { + systemSettings: SystemSettings; + userSettings: UserSettings; +} + +export interface SystemSettings { + info: Info; + urls: Urls; + featureFlags: FeatureFlags; +} + +export interface UserSettings { general: General; mapOptions: MmpOptions; } @@ -19,3 +30,18 @@ export interface Settings { interface General { language: string; } + +interface Info { + name: string; + version: string; +} + +interface Urls { + pictogramApiUrl: string; + pictogramStaticUrl: string; +} + +interface FeatureFlags { + pictograms: boolean; + ai: boolean; +} diff --git a/teammapper-frontend/src/assets/data/settings.json b/teammapper-frontend/src/assets/data/settings.json deleted file mode 100644 index d8bff052a..000000000 --- a/teammapper-frontend/src/assets/data/settings.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "general": { - "language": "de" - }, - "mapOptions": { - "centerOnResize": false, - "autoBranchColors": true, - "showLinktext": false, - "fontMaxSize": 70, - "fontMinSize": 15, - "fontIncrement": 5, - "defaultNode": { - "name": "", - "link": { - "href": "" - }, - "image": { - "src": "", - "size": 60 - }, - "colors": { - "name": "#666666", - "background": "#f5f5f5", - "branch": "#546e7a" - }, - "font": { - "size": 22, - "style": "normal", - "weight": "normal" - }, - "locked": true - }, - "rootNode": { - "name": "Thema", - "link": { - "href": "" - }, - "image": { - "src": "", - "size": 70 - }, - "colors": { - "name": "#666666", - "background": "#f5f5f5" - }, - "font": { - "size": 26, - "style": "normal", - "weight": "normal" - } - } - } -} diff --git a/teammapper-frontend/src/assets/i18n/de.json b/teammapper-frontend/src/assets/i18n/de.json index c03643b44..396d15146 100644 --- a/teammapper-frontend/src/assets/i18n/de.json +++ b/teammapper-frontend/src/assets/i18n/de.json @@ -135,6 +135,11 @@ }, "LINK": { "URL": "Link-URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "Verbindungsproblem", + "WARNING": "Ihre letzten Änderungen wurden möglicherweise nicht gespeichert.", + "RELOAD_BUTTON": "Seite neu laden" } }, "PAGES": { @@ -179,6 +184,8 @@ "GENERAL": "Allgemein", "MAIN": "Grundeinstellungen", "MAP_LIST": "Liste erstellter Mindmaps", + "OWNED_MAPS": "Meine Mindmaps", + "LAST_MAPS": "Zuletzt geöffnete Mindmaps", "MAP_OPTIONS": "Mindmap Optionen", "NODE_NAME": "Bezeichnung von Knoten", "ROOT_NODE_NAME": "Bezeichnung des Wurzelknotens", @@ -212,8 +219,8 @@ "ERRORS": { "ROOT_NODE_COPIED": "Es ist nicht möglich, den Hauptknoten zu kopieren!", "ROOT_NODE_CUT": "Es ist nicht möglich, den Hauptknoten zu auszuschneiden!", - "ROOT_NODE_DELETED": "Es ist nicht möglich, den Hauptknoten zu löschen!", - "ROOT_NODE_LOCKED": "Es ist nicht möglich, den Hauptknoten zu koppeln!", + "ROOT_NODE_DELETED": "Es ist nicht möglich, den Hauptknoten zu löschen!", + "ROOT_NODE_LOCKED": "Es ist nicht möglich, den Hauptknoten zu koppeln!", "NO_NODES_IN_CLIPBOARD": "Es sind keine Knoten in der Zwischenablage!", "NODE_COPY_GENERIC": "Beim Kopieren des Knotens ist ein Fehler aufgetreten.", "NODE_CUT_GENERIC": "Beim Ausschneiden des Knotens ist ein Fehler aufgetreten.", @@ -223,7 +230,15 @@ "EXPORT_IMAGE_ERROR": "Beim Bild-Export ist ein Fehler aufgetreten. Womöglich ist die Mindmap zu groß.", "MAP_COULD_NOT_BE_FOUND": "Mindmap konnte nicht gefunden werden!", "IMPORT_ERROR": "Mindmap konnte nicht importiert werden!", - "AI_MERMAID_ERROR": "Mermaid konnte nicht generiert werden." + "AI_MERMAID_ERROR": "Mermaid konnte nicht generiert werden.", + "OPERATION_FAILED_MAP_RELOADED": "Operation fehlgeschlagen - Karte vom Server neu geladen", + "NETWORK_TIMEOUT": "Die Verbindung zum Server wurde unterbrochen. Ihre Änderungen wurden möglicherweise nicht gespeichert.", + "SERVER_ERROR": "Der Server hat einen Fehler festgestellt. Ihre letzten Änderungen wurden möglicherweise nicht gespeichert.", + "AUTH_FAILED": "Authentifizierung fehlgeschlagen. Möglicherweise müssen Sie die Seite neu laden und sich erneut anmelden.", + "MALFORMED_REQUEST": "Es gab ein Problem mit Ihrer Anfrage. Bitte versuchen Sie es erneut.", + "RATE_LIMIT_EXCEEDED": "Zu viele Anfragen. Bitte warten Sie einen Moment, bevor Sie es erneut versuchen.", + "MALFORMED_RESPONSE": "Ungültige Antwort vom Server erhalten. Bitte laden Sie die Seite neu.", + "UNEXPECTED_ERROR": "Ein unerwarteter Fehler ist aufgetreten. Bitte laden Sie die Seite neu." }, "DELETE_MAP_SUCCESS": "Mindmap erfolgreich gelöscht!", "AI_MERMAID_GENERATED_SUCCESS": "Mermaid erfolgreich generiert", diff --git a/teammapper-frontend/src/assets/i18n/en.json b/teammapper-frontend/src/assets/i18n/en.json index 65e5b10eb..5eeb45a1b 100644 --- a/teammapper-frontend/src/assets/i18n/en.json +++ b/teammapper-frontend/src/assets/i18n/en.json @@ -135,6 +135,11 @@ }, "LINK": { "URL": "Link URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "Connection Issue", + "WARNING": "Your recent changes may not have been saved.", + "RELOAD_BUTTON": "Reload Page" } }, "PAGES": { @@ -179,6 +184,8 @@ "GENERAL": "General", "MAIN": "Main", "MAP_LIST": "List of created maps", + "OWNED_MAPS": "My mindmaps", + "LAST_MAPS": "Recently opened mindmaps", "MAP_OPTIONS": "Map options", "ROOT_NODE_NAME": "Root node name", "NODE_NAME": "Node name", @@ -222,7 +229,15 @@ "EXPORT_IMAGE_ERROR": "An error has occurred during image export. The mind map may be too large.", "MAP_COULD_NOT_BE_FOUND": "Mindmap could not be found!", "IMPORT_ERROR": "Could not import mindmap", - "AI_MERMAID_ERROR": "Mermaid could not be generated" + "AI_MERMAID_ERROR": "Mermaid could not be generated", + "OPERATION_FAILED_MAP_RELOADED": "Operation failed - map reloaded from server", + "NETWORK_TIMEOUT": "We lost connection to the server. Your changes may not have been saved.", + "SERVER_ERROR": "The server encountered an error. Your recent changes may not have been saved.", + "AUTH_FAILED": "Authentication failed. You may need to reload and sign in again.", + "MALFORMED_REQUEST": "There was a problem with your request. Please try again.", + "RATE_LIMIT_EXCEEDED": "Too many requests. Please wait a moment before trying again.", + "MALFORMED_RESPONSE": "Received invalid response from server. Please reload the page.", + "UNEXPECTED_ERROR": "An unexpected error occurred. Please reload the page." }, "DELETE_MAP_SUCCESS": "Mindmap successfully deleted!", "AI_MERMAID_GENERATED_SUCCESS": "Mermaid successfully generated!", diff --git a/teammapper-frontend/src/assets/i18n/es.json b/teammapper-frontend/src/assets/i18n/es.json index d93eaa7fe..6b382a330 100644 --- a/teammapper-frontend/src/assets/i18n/es.json +++ b/teammapper-frontend/src/assets/i18n/es.json @@ -134,6 +134,11 @@ }, "LINK": { "URL": "Link URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "Problema de conexión", + "WARNING": "Es posible que sus cambios recientes no se hayan guardado.", + "RELOAD_BUTTON": "Recargar página" } }, "PAGES": { @@ -178,6 +183,8 @@ "GENERAL": "General", "MAIN": "Principal", "MAP_LIST": "List of created maps", + "OWNED_MAPS": "Mis mapas mentales", + "LAST_MAPS": "Mapas mentales recientes", "MAP_OPTIONS": "Opciones del mapa", "ROOT_NODE_NAME": "Nombre del nodo raíz", "NODE_NAME": "Nombre del nodo", @@ -220,7 +227,15 @@ "EXPORT_IMAGE_ERROR": "Se ha producido un error durante la exportación de la imagen. El mapa mental puede ser demasiado grande.", "MAP_COULD_NOT_BE_FOUND": "No se ha encontrado el mapa mental.", "IMPORT_ERROR": "No se ha podido importar el mapa mental.", - "AI_MERMAID_ERROR": "No se pudo generar Mermaid" + "AI_MERMAID_ERROR": "No se pudo generar Mermaid", + "OPERATION_FAILED_MAP_RELOADED": "Operación fallida - mapa recargado desde el servidor", + "NETWORK_TIMEOUT": "Perdimos la conexión con el servidor. Es posible que sus cambios no se hayan guardado.", + "SERVER_ERROR": "El servidor encontró un error. Es posible que sus cambios recientes no se hayan guardado.", + "AUTH_FAILED": "Autenticación fallida. Es posible que deba recargar la página e iniciar sesión nuevamente.", + "MALFORMED_REQUEST": "Hubo un problema con su solicitud. Por favor, inténtelo de nuevo.", + "RATE_LIMIT_EXCEEDED": "Demasiadas solicitudes. Espere un momento antes de intentarlo de nuevo.", + "MALFORMED_RESPONSE": "Se recibió una respuesta inválida del servidor. Por favor, recargue la página.", + "UNEXPECTED_ERROR": "Ocurrió un error inesperado. Por favor, recargue la página." }, "DELETE_MAP_SUCCESS": "¡Mapa mental borrado con éxito!", "AI_MERMAID_GENERATED_SUCCESS": "¡Mermaid generado con éxito!", diff --git a/teammapper-frontend/src/assets/i18n/fr.json b/teammapper-frontend/src/assets/i18n/fr.json index 4cf3f0342..24d6a0875 100644 --- a/teammapper-frontend/src/assets/i18n/fr.json +++ b/teammapper-frontend/src/assets/i18n/fr.json @@ -134,6 +134,11 @@ }, "LINK": { "URL": "Link URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "Problème de connexion", + "WARNING": "Vos modifications récentes n'ont peut-être pas été enregistrées.", + "RELOAD_BUTTON": "Recharger la page" } }, "PAGES": { @@ -178,6 +183,8 @@ "GENERAL": "Général", "MAIN": "Principale", "MAP_LIST": "List of created maps", + "OWNED_MAPS": "Mes cartes mentales", + "LAST_MAPS": "Cartes mentales récentes", "MAP_OPTIONS": "Options de carte", "ROOT_NODE_NAME": "Nom du noeud racine", "NODE_NAME": "Nom du noeud", @@ -211,7 +218,7 @@ "ROOT_NODE_CUT": "Il n'est pas possible de couper le nœud racine !", "ROOT_NODE_DELETED": "Il est impossible de supprimer le nœud racine !", "ROOT_NODE_LOCKED": "Il est impossible de verrouiller le nœud racine !", - "NO_NODES_IN_CLIPBOARD": "Il n’y a aucun nœud dans le presse-papiers !", + "NO_NODES_IN_CLIPBOARD": "Il n'y a aucun nœud dans le presse-papiers !", "NODE_COPY_GENERIC": "Une erreur s'est produite lors de la copie du nœud.", "NODE_CUT_GENERIC": "Une erreur s'est produite lors de la découpe du nœud.", "NODE_DELETION_GENERIC": "Une erreur est survenue lors de la suppression du nœud.", @@ -220,7 +227,15 @@ "EXPORT_IMAGE_ERROR": "Une erreur s'est produite lors de l'exportation de l'image. Il se peut que la mind map soit trop grande.", "MAP_COULD_NOT_BE_FOUND": "La carte heuristique est introuvable !", "IMPORT_ERROR": "La Mindmap n'a pas pu être importée !", - "AI_MERMAID_ERROR": "Mermaid n'a pas pu être généré" + "AI_MERMAID_ERROR": "Mermaid n'a pas pu être généré", + "OPERATION_FAILED_MAP_RELOADED": "Opération échouée - carte rechargée depuis le serveur", + "NETWORK_TIMEOUT": "Nous avons perdu la connexion au serveur. Vos modifications n'ont peut-être pas été enregistrées.", + "SERVER_ERROR": "Le serveur a rencontré une erreur. Vos modifications récentes n'ont peut-être pas été enregistrées.", + "AUTH_FAILED": "Échec de l'authentification. Vous devrez peut-être recharger la page et vous reconnecter.", + "MALFORMED_REQUEST": "Il y a eu un problème avec votre demande. Veuillez réessayer.", + "RATE_LIMIT_EXCEEDED": "Trop de demandes. Veuillez patienter un instant avant de réessayer.", + "MALFORMED_RESPONSE": "Réponse invalide reçue du serveur. Veuillez recharger la page.", + "UNEXPECTED_ERROR": "Une erreur inattendue s'est produite. Veuillez recharger la page." }, "DELETE_MAP_SUCCESS": "Mindmap supprimée avec succès !", "AI_MERMAID_GENERATED_SUCCESS": "Mermaid généré avec succès !", diff --git a/teammapper-frontend/src/assets/i18n/it.json b/teammapper-frontend/src/assets/i18n/it.json index a06df114d..f810c8dd1 100644 --- a/teammapper-frontend/src/assets/i18n/it.json +++ b/teammapper-frontend/src/assets/i18n/it.json @@ -134,6 +134,11 @@ }, "LINK": { "URL": "Link URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "Problema di connessione", + "WARNING": "Le modifiche recenti potrebbero non essere state salvate.", + "RELOAD_BUTTON": "Ricarica pagina" } }, "PAGES": { @@ -178,6 +183,8 @@ "GENERAL": "Generali", "MAIN": "Principali", "MAP_LIST": "Elenco delle mappe create", + "OWNED_MAPS": "Le mie mappe mentali", + "LAST_MAPS": "Mappe mentali recenti", "MAP_OPTIONS": "Opzioni mappa", "ROOT_NODE_NAME": "Nome nodo radice", "NODE_NAME": "Nome nodo", @@ -214,13 +221,21 @@ "NO_NODES_IN_CLIPBOARD": "Non ci sono nodi negli appunti!", "NODE_COPY_GENERIC": "Si è verificato un errore durante il tentativo di copiare il nodo.", "NODE_CUT_GENERIC": "Si è verificato un errore durante il tentativo di tagliare il nodo.", - "NODE_DELETION_GENERIC": "Si è verificato un errore durante l’eliminazione del nodo.", - "NODE_UPDATE_GENERIC": "Si è verificato un errore durante l’aggiornamento del nodo.", - "NODE_PASTE_GENERIC": "Si è verificato un errore durante l’incolla dei nodi.", + "NODE_DELETION_GENERIC": "Si è verificato un errore durante l'eliminazione del nodo.", + "NODE_UPDATE_GENERIC": "Si è verificato un errore durante l'aggiornamento del nodo.", + "NODE_PASTE_GENERIC": "Si è verificato un errore durante l'incolla dei nodi.", "EXPORT_IMAGE_ERROR": "Si è verificato un errore durante l'esportazione dell'immagine. La mappa mentale potrebbe essere troppo grande.", "MAP_COULD_NOT_BE_FOUND": "Impossibile trovare la mappa mentale!", "IMPORT_ERROR": "Non è stato possibile importare la mappa mentale!", - "AI_MERMAID_ERROR": "Mermaid non può essere generato" + "AI_MERMAID_ERROR": "Mermaid non può essere generato", + "OPERATION_FAILED_MAP_RELOADED": "Operazione fallita - mappa ricaricata dal server", + "NETWORK_TIMEOUT": "Abbiamo perso la connessione al server. Le tue modifiche potrebbero non essere state salvate.", + "SERVER_ERROR": "Il server ha riscontrato un errore. Le tue modifiche recenti potrebbero non essere state salvate.", + "AUTH_FAILED": "Autenticazione fallita. Potrebbe essere necessario ricaricare la pagina e accedere nuovamente.", + "MALFORMED_REQUEST": "Si è verificato un problema con la tua richiesta. Riprova.", + "RATE_LIMIT_EXCEEDED": "Troppe richieste. Attendi un momento prima di riprovare.", + "MALFORMED_RESPONSE": "Ricevuta risposta non valida dal server. Ricarica la pagina.", + "UNEXPECTED_ERROR": "Si è verificato un errore imprevisto. Ricarica la pagina." }, "DELETE_MAP_SUCCESS": "Mappa mentale cancellata con successo!", "AI_MERMAID_GENERATED_SUCCESS": "Mermaid generato con successo!", diff --git a/teammapper-frontend/src/assets/i18n/pt-br.json b/teammapper-frontend/src/assets/i18n/pt-br.json index ba881fd3d..da3735951 100644 --- a/teammapper-frontend/src/assets/i18n/pt-br.json +++ b/teammapper-frontend/src/assets/i18n/pt-br.json @@ -134,6 +134,11 @@ }, "LINK": { "URL": "Link URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "Problema de conexão", + "WARNING": "Suas alterações recentes podem não ter sido salvas.", + "RELOAD_BUTTON": "Recarregar página" } }, "PAGES": { @@ -178,6 +183,8 @@ "GENERAL": "Geral", "MAIN": "Principal", "MAP_LIST": "List of created maps", + "OWNED_MAPS": "Meus mapas mentais", + "LAST_MAPS": "Mapas mentais recentes", "MAP_OPTIONS": "Opções de mapa", "ROOT_NODE_NAME": "Nome do nó raiz", "NODE_NAME": "Nome do nó", @@ -220,7 +227,15 @@ "EXPORT_IMAGE_ERROR": "Ocorreu um erro durante a exportação da imagem. O mapa mental pode ser muito grande.", "MAP_COULD_NOT_BE_FOUND": "Não foi possível encontrar o mapa mental!", "IMPORT_ERROR": "O mapa mental não pôde ser importado!", - "AI_MERMAID_ERROR": "Mermaid não pôde ser gerado" + "AI_MERMAID_ERROR": "Mermaid não pôde ser gerado", + "OPERATION_FAILED_MAP_RELOADED": "Operação falhou - mapa recarregado do servidor", + "NETWORK_TIMEOUT": "Perdemos a conexão com o servidor. Suas alterações podem não ter sido salvas.", + "SERVER_ERROR": "O servidor encontrou um erro. Suas alterações recentes podem não ter sido salvas.", + "AUTH_FAILED": "Autenticação falhou. Você pode precisar recarregar a página e fazer login novamente.", + "MALFORMED_REQUEST": "Houve um problema com sua solicitação. Por favor, tente novamente.", + "RATE_LIMIT_EXCEEDED": "Muitas solicitações. Aguarde um momento antes de tentar novamente.", + "MALFORMED_RESPONSE": "Resposta inválida recebida do servidor. Por favor, recarregue a página.", + "UNEXPECTED_ERROR": "Ocorreu um erro inesperado. Por favor, recarregue a página." }, "DELETE_MAP_SUCCESS": "Mapa mental excluído com sucesso!", "AI_MERMAID_GENERATED_SUCCESS": "Mermaid gerado com sucesso!", diff --git a/teammapper-frontend/src/assets/i18n/zh-cn.json b/teammapper-frontend/src/assets/i18n/zh-cn.json index ddc0be7b0..523551b92 100644 --- a/teammapper-frontend/src/assets/i18n/zh-cn.json +++ b/teammapper-frontend/src/assets/i18n/zh-cn.json @@ -134,6 +134,11 @@ }, "LINK": { "URL": "链接 URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "连接问题", + "WARNING": "您最近的更改可能未保存。", + "RELOAD_BUTTON": "重新加载页面" } }, "PAGES": { @@ -178,6 +183,8 @@ "GENERAL": "一般", "MAIN": "主界面", "MAP_LIST": "已创建思维导图列表", + "OWNED_MAPS": "我的思维导图", + "LAST_MAPS": "最近打开的思维导图", "MAP_OPTIONS": "思维导图选项", "ROOT_NODE_NAME": "根节点名称", "NODE_NAME": "节点名称", @@ -220,7 +227,15 @@ "EXPORT_IMAGE_ERROR": "导出图像时发生错误。思维导图可能过大。", "MAP_COULD_NOT_BE_FOUND": "找不到思维导图!", "IMPORT_ERROR": "无法导入思维导图!", - "AI_MERMAID_ERROR": "无法生成Mermaid" + "AI_MERMAID_ERROR": "无法生成Mermaid", + "OPERATION_FAILED_MAP_RELOADED": "操作失败 - 已从服务器重新加载地图", + "NETWORK_TIMEOUT": "我们与服务器失去了连接。您的更改可能尚未保存。", + "SERVER_ERROR": "服务器遇到错误。您最近的更改可能尚未保存。", + "AUTH_FAILED": "身份验证失败。您可能需要重新加载页面并重新登录。", + "MALFORMED_REQUEST": "您的请求出现问题。请重试。", + "RATE_LIMIT_EXCEEDED": "请求过多。请稍等片刻再试。", + "MALFORMED_RESPONSE": "从服务器收到无效响应。请重新加载页面。", + "UNEXPECTED_ERROR": "发生意外错误。请重新加载页面。" }, "DELETE_MAP_SUCCESS": "思维导图已成功删除!", "AI_MERMAID_GENERATED_SUCCESS": "Mermaid生成成功!", diff --git a/teammapper-frontend/src/assets/i18n/zh-tw.json b/teammapper-frontend/src/assets/i18n/zh-tw.json index 5c8a30ce2..ba2bc637c 100644 --- a/teammapper-frontend/src/assets/i18n/zh-tw.json +++ b/teammapper-frontend/src/assets/i18n/zh-tw.json @@ -134,6 +134,11 @@ }, "LINK": { "URL": "Link URL (https://...)" + }, + "CRITICAL_ERROR": { + "TITLE": "連線問題", + "WARNING": "您最近的變更可能未儲存。", + "RELOAD_BUTTON": "重新載入頁面" } }, "PAGES": { @@ -178,6 +183,8 @@ "GENERAL": "一般", "MAIN": "主畫面", "MAP_LIST": "List of created maps", + "OWNED_MAPS": "我的心智圖", + "LAST_MAPS": "最近開啟的心智圖", "MAP_OPTIONS": "地圖選項", "ROOT_NODE_NAME": "根節點名稱", "NODE_NAME": "節點名稱", @@ -220,7 +227,15 @@ "EXPORT_IMAGE_ERROR": "An error has occurred during image export. The mind map may be too large.", "MAP_COULD_NOT_BE_FOUND": "Mindmap could not be found!", "IMPORT_ERROR": "Mindmap could not be imported!", - "AI_MERMAID_ERROR": "無法生成Mermaid" + "AI_MERMAID_ERROR": "無法生成Mermaid", + "OPERATION_FAILED_MAP_RELOADED": "操作失敗 - 已從伺服器重新載入地圖", + "NETWORK_TIMEOUT": "我們與伺服器失去連接。您的變更可能尚未儲存。", + "SERVER_ERROR": "伺服器遇到錯誤。您最近的變更可能尚未儲存。", + "AUTH_FAILED": "身份驗證失敗。您可能需要重新載入頁面並重新登入。", + "MALFORMED_REQUEST": "您的請求出現問題。請重試。", + "RATE_LIMIT_EXCEEDED": "請求過多。請稍等片刻再試。", + "MALFORMED_RESPONSE": "從伺服器收到無效回應。請重新載入頁面。", + "UNEXPECTED_ERROR": "發生意外錯誤。請重新載入頁面。" }, "DELETE_MAP_SUCCESS": "Mindmap successfully deleted!", "AI_MERMAID_GENERATED_SUCCESS": "Mermaid生成成功!", diff --git a/teammapper-frontend/src/environments/environment.prod.ts b/teammapper-frontend/src/environments/environment.prod.ts index d140b89b7..156d77a24 100644 --- a/teammapper-frontend/src/environments/environment.prod.ts +++ b/teammapper-frontend/src/environments/environment.prod.ts @@ -1,10 +1,4 @@ export const environment = { production: true, - settingsFilePath: 'settings.json', - version: '0.1.9', - name: 'TeamMapper', - pictogramApiUrl: '/arasaac/api/pictograms', - pictogramStaticUrl: '/arasaac/images/pictograms', - featureFlagPictograms: true, featureFlagAI: true, }; diff --git a/teammapper-frontend/src/environments/environment.ts b/teammapper-frontend/src/environments/environment.ts index 8280ae24a..a20cfe557 100644 --- a/teammapper-frontend/src/environments/environment.ts +++ b/teammapper-frontend/src/environments/environment.ts @@ -1,10 +1,3 @@ export const environment = { production: false, - settingsFilePath: 'originalSettings.json', - version: '0.4.0', - name: 'TeamMapper', - pictogramApiUrl: 'https://api.arasaac.org/v1/pictograms', - pictogramStaticUrl: 'https://static.arasaac.org/pictograms', - featureFlagPictograms: true, - featureFlagAI: true, }; diff --git a/teammapper-frontend/src/test/mocks/utils-service.mock.ts b/teammapper-frontend/src/test/mocks/utils-service.mock.ts new file mode 100644 index 000000000..eee48b55c --- /dev/null +++ b/teammapper-frontend/src/test/mocks/utils-service.mock.ts @@ -0,0 +1,51 @@ +import { UtilsService } from '../../app/core/services/utils/utils.service'; + +/** + * Centralized translation keys for tests + * Keeps test translations consistent with production keys + */ +export const MOCK_TRANSLATIONS: Record = { + 'TOASTS.ERRORS.OPERATION_FAILED_MAP_RELOADED': + 'Operation failed - map reloaded from server', + 'TOASTS.ERRORS.MALFORMED_RESPONSE': + 'Received invalid response from server. Please reload the page.', + 'TOASTS.ERRORS.SERVER_ERROR': + 'The server encountered an error. Your recent changes may not have been saved.', + 'TOASTS.ERRORS.NETWORK_TIMEOUT': + 'We lost connection to the server. Your changes may not have been saved.', + 'TOASTS.ERRORS.AUTH_FAILED': + 'Authentication failed. You may need to reload and sign in again.', + 'TOASTS.ERRORS.MALFORMED_REQUEST': + 'There was a problem with your request. Please try again.', + 'TOASTS.ERRORS.RATE_LIMIT_EXCEEDED': + 'Too many requests. Please wait a moment before trying again.', + 'TOASTS.ERRORS.UNEXPECTED_ERROR': + 'An unexpected error occurred. Please reload the page.', +}; + +/** + * Creates a properly configured mock UtilsService for testing + * Includes all instance methods with sensible defaults + * + * @returns Jest mock object with configured translate method + */ +export function createMockUtilsService(): jest.Mocked { + const mock = { + translate: jest.fn(), + confirmDialog: jest.fn(), + blobToBase64: jest.fn(), + } as unknown as jest.Mocked; + + // Configure translate spy with realistic return values + mock.translate.mockImplementation(async (key: string) => { + return MOCK_TRANSLATIONS[key] || key; + }); + + // Configure confirmDialog with default behavior (returns true) + mock.confirmDialog.mockResolvedValue(true); + + // Configure blobToBase64 with default behavior + mock.blobToBase64.mockResolvedValue('data:image/png;base64,mock'); + + return mock; +} diff --git a/teammapper-frontend/src/tsconfig.spec.json b/teammapper-frontend/src/tsconfig.spec.json index 6c0390d17..59430ef1d 100644 --- a/teammapper-frontend/src/tsconfig.spec.json +++ b/teammapper-frontend/src/tsconfig.spec.json @@ -3,7 +3,7 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", - "types": ["jest"] + "types": ["jest", "node"] }, "files": ["polyfills.ts"], "include": ["./**/*.spec.ts", "./**/*.d.ts"]