diff --git a/.devcontainer/api/devcontainer.json b/.devcontainer/api/devcontainer.json new file mode 100644 index 0000000000..4002a26b14 --- /dev/null +++ b/.devcontainer/api/devcontainer.json @@ -0,0 +1,51 @@ +{ + "name": "Tracker API", + "dockerComposeFile": "docker-compose.yml", + + // The service in docker-compose that VS Code / Codespaces attaches to + "service": "api", + + // Set the workspace to the api subdirectory of the monorepo. + // docker-compose.yml mounts the repo root at /workspaces, so api/ is at /workspaces/api. + "workspaceFolder": "/workspaces/api", + + "forwardPorts": [4000, 8529, 4222], + "portsAttributes": { + "4000": { + "label": "GraphQL API", + "onAutoForward": "notify" + }, + "8529": { + "label": "ArangoDB Web UI" + }, + "4222": { + "label": "NATS" + } + }, + + // Install dependencies after the container is created. + // Copy .env.example to .env so the API can start without manual setup. + "postCreateCommand": "npm install && [ ! -f .env ] && cp .env.example .env || true", + + // Start the API in watch mode automatically + "postStartCommand": "npm run dev:watch", + + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "apollographql.vscode-apollo", + "lokalise.i18n-ally", + "Orta.vscode-jest" + ], + "settings": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "eslint.workingDirectories": ["."] + } + } + }, + + "remoteUser": "node" +} diff --git a/.devcontainer/api/docker-compose.yml b/.devcontainer/api/docker-compose.yml new file mode 100644 index 0000000000..9107f66e06 --- /dev/null +++ b/.devcontainer/api/docker-compose.yml @@ -0,0 +1,88 @@ +version: "3.8" + +services: + api: + image: mcr.microsoft.com/devcontainers/javascript-node:20 + volumes: + # Mount the monorepo root so all relative paths within the project work + - ../..:/workspaces:cached + command: sleep infinity + environment: + - NODE_ENV=development + - DB_URL=http://arangodb:8529 + - DB_NAME=track_dmarc + - DB_PASS=test + - NATS_URL=nats://nats:4222 + depends_on: + - arangodb + - nats + networks: + - tracker-dev + + arangodb: + image: arangodb:3.12.1 + environment: + - ARANGO_ROOT_PASSWORD=test + volumes: + - arangodb-data:/var/lib/arangodb3 + networks: + - tracker-dev + + nats: + image: nats:2.10.16-scratch + command: -js + networks: + - tracker-dev + + nats-init: + image: natsio/nats-box:latest + depends_on: + - nats + volumes: + - ../../k8s/infrastructure/bases/nats/stream-config.json:/stream-config/stream-config.json + entrypoint: > + /bin/sh -c ' + set -e + echo "[nats-stream-init] Waiting for NATS..." + until nc -z nats 4222; do + sleep 1 + done + sleep 2 + + echo "[nats-stream-init] Attempting to add SCANS stream..." + if nats stream add SCANS --config /stream-config/stream-config.json --server nats://nats:4222; then + echo "[nats-stream-init] SCANS stream added successfully." + else + echo "[nats-stream-init] Add failed, attempting to edit SCANS stream..." + if nats stream edit SCANS --config /stream-config/stream-config.json --server nats://nats:4222 --force; then + echo "[nats-stream-init] SCANS stream edited successfully." + else + echo "[nats-stream-init] ERROR: Could not add or edit SCANS stream!" + exit 1 + fi + fi + + echo "[nats-stream-init] Attempting to add WEB_SCANNER_IPS KV bucket..." + if nats kv add "WEB_SCANNER_IPS" --ttl="5m" --server nats://nats:4222; then + echo "[nats-stream-init] WEB_SCANNER_IPS KV bucket added successfully." + else + echo "[nats-stream-init] Add failed, attempting to edit WEB_SCANNER_IPS KV bucket..." + if nats kv edit "WEB_SCANNER_IPS" --ttl="5m" --server nats://nats:4222; then + echo "[nats-stream-init] WEB_SCANNER_IPS KV bucket edited successfully." + else + echo "[nats-stream-init] ERROR: Could not add or edit WEB_SCANNER_IPS KV bucket!" + exit 1 + fi + fi + + echo "[nats-stream-init] Stream initialization complete." + exec sleep infinity + ' + networks: + - tracker-dev + +networks: + tracker-dev: + +volumes: + arangodb-data: diff --git a/.devcontainer/frontend/devcontainer.json b/.devcontainer/frontend/devcontainer.json new file mode 100644 index 0000000000..77ee852119 --- /dev/null +++ b/.devcontainer/frontend/devcontainer.json @@ -0,0 +1,43 @@ +{ + "name": "Tracker Frontend", + "image": "mcr.microsoft.com/devcontainers/javascript-node:20", + + // Set the workspace to the frontend subdirectory of the monorepo + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/frontend", + + "forwardPorts": [3000, 3001], + "portsAttributes": { + "3000": { + "label": "Frontend Dev Server", + "onAutoForward": "openBrowser" + }, + "3001": { + "label": "Webpack Dev Server (internal)" + } + }, + + // Install dependencies after the container is created + "postCreateCommand": "npm install", + + // Start the dev server automatically when the container starts + "postStartCommand": "npm run dev", + + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "dsznajder.es7-react-js-snippets", + "apollographql.vscode-apollo", + "lokalise.i18n-ally" + ], + "settings": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "eslint.workingDirectories": ["./frontend"] + } + } + }, + + "remoteUser": "node" +} diff --git a/.devcontainer/scanners/devcontainer.json b/.devcontainer/scanners/devcontainer.json new file mode 100644 index 0000000000..3367865336 --- /dev/null +++ b/.devcontainer/scanners/devcontainer.json @@ -0,0 +1,46 @@ +{ + "name": "Tracker Scanners", + "dockerComposeFile": "docker-compose.yml", + + // The service in docker-compose that VS Code / Codespaces attaches to + "service": "dev", + + // docker-compose.yml mounts the repo root at /workspaces, so scanners/ is at /workspaces/scanners. + "workspaceFolder": "/workspaces/scanners", + + "forwardPorts": [8529, 8222], + "portsAttributes": { + "8529": { + "label": "ArangoDB Web UI" + }, + "8222": { + "label": "NATS Monitor" + } + }, + + // Install the NATS CLI for injecting test messages, then set up a venv per service. + // + // Each service pins its own Python version. The Microsoft Python devcontainer image + // ships with pyenv, so we install the versions that differ from the container's + // default (3.14) and create isolated venvs per service directory. + // + // python-dotenv will not override env vars already set in docker-compose, so the + // container-friendly host names (arangodb, nats) take precedence over any localhost + // values in local .env files. + "postCreateCommand": "bash /workspaces/.devcontainer/scanners/setup.sh", + + "customizations": { + "vscode": { + "extensions": ["ms-python.python", "ms-python.vscode-pylance", "ms-python.debugpy", "ms-python.black-formatter"], + "settings": { + "editor.formatOnSave": true, + "python.defaultInterpreterPath": "${workspaceFolder}/dns-scanner/.venv/bin/python", + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter" + } + } + } + }, + + "remoteUser": "vscode" +} diff --git a/.devcontainer/scanners/docker-compose.yml b/.devcontainer/scanners/docker-compose.yml new file mode 100644 index 0000000000..2b8cd12174 --- /dev/null +++ b/.devcontainer/scanners/docker-compose.yml @@ -0,0 +1,89 @@ +version: "3.8" + +services: + dev: + image: mcr.microsoft.com/devcontainers/python:dev-3.14-bookworm + volumes: + # Mount the monorepo root so all relative paths within the project work + - ../..:/workspaces:cached + command: sleep infinity + environment: + # Override localhost defaults so services connect to named containers + - DB_USER=root + - DB_PASS=test + - DB_NAME=track_dmarc + - DB_URL=http://arangodb:8529 + - NATS_SERVERS=nats://nats:4222 + depends_on: + - arangodb + - nats + networks: + - tracker-dev + + arangodb: + image: arangodb:3.12.1 + environment: + - ARANGO_ROOT_PASSWORD=test + volumes: + - arangodb-data:/var/lib/arangodb3 + networks: + - tracker-dev + + nats: + image: nats:2.10.16-scratch + command: -js + networks: + - tracker-dev + + nats-init: + image: natsio/nats-box:latest + depends_on: + - nats + volumes: + - ../../k8s/infrastructure/bases/nats/stream-config.json:/stream-config/stream-config.json + entrypoint: > + /bin/sh -c ' + set -e + echo "[nats-stream-init] Waiting for NATS..." + until nc -z nats 4222; do + sleep 1 + done + sleep 2 + + echo "[nats-stream-init] Attempting to add SCANS stream..." + if nats stream add SCANS --config /stream-config/stream-config.json --server nats://nats:4222; then + echo "[nats-stream-init] SCANS stream added successfully." + else + echo "[nats-stream-init] Add failed, attempting to edit SCANS stream..." + if nats stream edit SCANS --config /stream-config/stream-config.json --server nats://nats:4222 --force; then + echo "[nats-stream-init] SCANS stream edited successfully." + else + echo "[nats-stream-init] ERROR: Could not add or edit SCANS stream!" + exit 1 + fi + fi + + echo "[nats-stream-init] Attempting to add WEB_SCANNER_IPS KV bucket..." + if nats kv add "WEB_SCANNER_IPS" --ttl="5m" --server nats://nats:4222; then + echo "[nats-stream-init] WEB_SCANNER_IPS KV bucket added successfully." + else + echo "[nats-stream-init] Add failed, attempting to edit WEB_SCANNER_IPS KV bucket..." + if nats kv edit "WEB_SCANNER_IPS" --ttl="5m" --server nats://nats:4222; then + echo "[nats-stream-init] WEB_SCANNER_IPS KV bucket edited successfully." + else + echo "[nats-stream-init] ERROR: Could not add or edit WEB_SCANNER_IPS KV bucket!" + exit 1 + fi + fi + + echo "[nats-stream-init] Stream initialization complete." + exec sleep infinity + ' + networks: + - tracker-dev + +networks: + tracker-dev: + +volumes: + arangodb-data: diff --git a/.devcontainer/scanners/setup.sh b/.devcontainer/scanners/setup.sh new file mode 100644 index 0000000000..4bb1ecfa16 --- /dev/null +++ b/.devcontainer/scanners/setup.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +set -euo pipefail + +# The script lives at .devcontainer/scanners/setup.sh — two dirs up is the repo root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +SCANNERS_DIR="$REPO_ROOT/scanners" + +# --------------------------------------------------------------------------- +# NATS CLI — useful for publishing test messages and inspecting streams +# --------------------------------------------------------------------------- +echo ">>> Installing NATS CLI..." +NATS_VERSION="0.2.2" +ARCH="$(dpkg --print-architecture)" # amd64 or arm64 +curl -fsSL "https://github.com/nats-io/natscli/releases/download/v${NATS_VERSION}/nats-${NATS_VERSION}-linux-${ARCH}.zip" \ + -o /tmp/nats.zip +unzip -q /tmp/nats.zip -d /tmp/nats +sudo mv /tmp/nats/nats-*/nats /usr/local/bin/nats +rm -rf /tmp/nats /tmp/nats.zip +echo " nats $(nats --version)" + +# --------------------------------------------------------------------------- +# pyenv — install if not already present, then bootstrap for this session. +# Each scanner service pins its own Python version in its Dockerfile; we +# use pyenv to create isolated venvs per service without touching system Python. +# --------------------------------------------------------------------------- +export PYENV_ROOT="$HOME/.pyenv" +if [ ! -x "$PYENV_ROOT/bin/pyenv" ]; then + echo ">>> Installing build dependencies..." + # Required to compile CPython (pyenv) and native Python extensions (e.g. pydantic-core) + sudo apt-get update -qq + sudo apt-get install -y -qq \ + build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev \ + libsqlite3-dev libffi-dev liblzma-dev libncurses-dev + + echo ">>> Installing Rust (required for pydantic-core and other native extensions)..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path + # Source immediately so cargo is available for the rest of this block + source "$HOME/.cargo/env" + + echo ">>> Installing pyenv..." + curl -fsSL https://pyenv.run | bash + + echo ">>> Installing rust-query-crlite (used by web-scanner for TLS revocation checks)..." + cargo install \ + --git https://github.com/mozilla/crlite rust-query-crlite \ + --tag v1.0.39 +fi + +# Make Rust and pyenv available for this session +export PATH="$HOME/.cargo/bin:$PATH" +export PATH="$PYENV_ROOT/bin:$PATH" +eval "$(pyenv init --path)" + +# Map service → Python version (sourced from each service's Dockerfile) +declare -A SERVICE_PYTHON=( + [dns-scanner]="3.13.5" + [dns-processor]="3.14.2" + [web-scanner]="3.12.8" + [web-processor]="3.14.2" +) + +for service in "${!SERVICE_PYTHON[@]}"; do + version="${SERVICE_PYTHON[$service]}" + svc_dir="$SCANNERS_DIR/$service" + + echo ">>> [$service] Setting up Python $version venv..." + + # Install the version if pyenv doesn't have it yet. + # --enable-shared is required for maturin/pyo3 (e.g. pydantic-core) to link + # against libpython. Without it, maturin ignores the venv and falls back to + # the system Python, causing version mismatches and build failures. + if ! pyenv versions --bare | grep -qx "$version"; then + PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install "$version" + fi + + # Create venv using the pinned version + "$PYENV_ROOT/versions/$version/bin/python" -m venv "$svc_dir/.venv" + + # Install dependencies + "$svc_dir/.venv/bin/pip" install --quiet --upgrade pip + "$svc_dir/.venv/bin/pip" install --quiet -r "$svc_dir/requirements.txt" + + # Copy .env.example → .env if no .env exists yet + if [ ! -f "$svc_dir/.env" ] && [ -f "$svc_dir/.env.example" ]; then + cp "$svc_dir/.env.example" "$svc_dir/.env" + echo " Copied .env.example → .env (fill in secrets before running)" + fi + + echo " Done." +done + +echo "" +echo "Setup complete. Tips:" +echo " • cd into a service directory and activate its venv: source .venv/bin/activate" +echo " • Run the service: python service.py" +echo " • Publish a test scan request via NATS CLI:" +echo " nats pub --server nats://nats:4222 scans.requests '{\"domain\": \"example.com\"}'" +echo " • Inspect the SCANS stream:" +echo " nats stream info SCANS --server nats://nats:4222" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e5e1dd745a..c90437abd7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,235 +1,393 @@ version: 2 + updates: + # Monday — frontend (standalone, largest dep file) - package-ecosystem: docker - directory: "/api" + directory: "/frontend" schedule: - interval: daily + interval: weekly + day: monday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: npm - directory: "/api" - schedule: - interval: daily - time: "11:00" - open-pull-requests-limit: 5 - - - package-ecosystem: pip - directory: "/clients/python" + directory: "/frontend" schedule: - interval: daily + interval: weekly + day: monday time: "11:00" - open-pull-requests-limit: 0 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 + # Tuesday — api (standalone, large dep file) - package-ecosystem: docker - directory: "/frontend" + directory: "/api" schedule: - interval: daily + interval: weekly + day: tuesday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: npm - directory: "/frontend" + directory: "/api" schedule: - interval: daily + interval: weekly + day: tuesday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - # scanners - - package-ecosystem: pip - directory: "/scanners/web-scanner" + # Wednesday — dmarc-report + super-admin (medium services) + - package-ecosystem: docker + directory: "/services/dmarc-report" schedule: - interval: daily + interval: weekly + day: wednesday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - - package-ecosystem: docker - directory: "/scanners/web-scanner" + - package-ecosystem: npm + directory: "/services/dmarc-report" schedule: - interval: daily + interval: weekly + day: wednesday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker - directory: "/scanners/dns-scanner" + directory: "/services/super-admin" schedule: - interval: daily + interval: weekly + day: wednesday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - - package-ecosystem: pip - directory: "/scanners/dns-scanner" + - package-ecosystem: npm + directory: "/services/super-admin" schedule: - interval: daily + interval: weekly + day: wednesday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 + # Thursday — domain-cleanup + org-footprint (medium services) - package-ecosystem: docker - directory: "/scanners/domain-discovery" + directory: "/services/domain-cleanup" schedule: - interval: daily + interval: weekly + day: thursday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - - package-ecosystem: pip - directory: "/scanners/domain-discovery" + - package-ecosystem: npm + directory: "/services/domain-cleanup" schedule: - interval: daily + interval: weekly + day: thursday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker - directory: "/scanners/domain-dispatcher" + directory: "/services/org-footprint" schedule: - interval: daily + interval: weekly + day: thursday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: npm - directory: "/scanners/domain-dispatcher" + directory: "/services/org-footprint" schedule: - interval: daily + interval: weekly + day: thursday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - # services + # Friday — progress-report + domain-dispatcher (medium services) - package-ecosystem: docker - directory: "/services/dmarc-report" + directory: "/services/progress-report" schedule: - interval: daily + interval: weekly + day: friday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: npm - directory: "/services/dmarc-report" + directory: "/services/progress-report" schedule: - interval: daily + interval: weekly + day: friday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker - directory: "/services/super-admin" + directory: "/scanners/domain-dispatcher" schedule: - interval: daily + interval: weekly + day: friday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: npm - directory: "/services/super-admin" + directory: "/scanners/domain-dispatcher" schedule: - interval: daily + interval: weekly + day: friday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 + # Saturday — web-scanner + dns-scanner + domain-discovery (small scanners) - package-ecosystem: docker - directory: "/services/domain-cleanup" + directory: "/scanners/web-scanner" schedule: - interval: daily + interval: weekly + day: saturday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - - package-ecosystem: npm - directory: "/services/domain-cleanup" + - package-ecosystem: pip + directory: "/scanners/web-scanner" schedule: - interval: daily + interval: weekly + day: saturday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker - directory: "/services/org-footprint" + directory: "/scanners/dns-scanner" schedule: - interval: daily + interval: weekly + day: saturday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - - package-ecosystem: npm - directory: "/services/org-footprint" + - package-ecosystem: pip + directory: "/scanners/dns-scanner" schedule: - interval: daily + interval: weekly + day: saturday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker - directory: "/services/progress-report" + directory: "/scanners/domain-discovery" schedule: - interval: daily + interval: weekly + day: saturday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - - package-ecosystem: npm - directory: "/services/progress-report" + - package-ecosystem: pip + directory: "/scanners/domain-discovery" schedule: - interval: daily + interval: weekly + day: saturday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 + # Sunday — update-selectors + summaries + azure-defender-easm (smallest services) - package-ecosystem: docker directory: "/services/update-selectors" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: pip directory: "/services/update-selectors" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker directory: "/services/summaries" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: pip directory: "/services/summaries" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - # azure-defender-easm - package-ecosystem: docker directory: "/azure-defender-easm/import-easm-additional-findings" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: pip directory: "/azure-defender-easm/import-easm-additional-findings" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker directory: "/azure-defender-easm/label-known-easm-assets" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: pip directory: "/azure-defender-easm/label-known-easm-assets" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: docker directory: "/azure-defender-easm/add-domain-to-easm" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 - package-ecosystem: pip directory: "/azure-defender-easm/add-domain-to-easm" schedule: - interval: daily + interval: weekly + day: sunday time: "11:00" - open-pull-requests-limit: 5 + open-pull-requests-limit: 3 + cooldown: + default-days: 7 + semver-minor-days: 14 + semver-major-days: 30 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 916f5fcd64..b3d26e2bcc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,50 +1,50 @@ -name: "CodeQL" +name: CodeQL - Analysis on: + push: + branches: ["master"] + pull_request: + branches: ["master"] schedule: - # Run every Tuesday + # Run every Tuesday at 00:00 UTC - cron: "0 0 * * 2" +concurrency: + group: codeql-${{ github.ref }} + cancel-in-progress: true + +permissions: + security-events: write + actions: read + contents: read + jobs: analyze: - name: Analyze + name: Analyze (${{ matrix.language }}) runs-on: ubuntu-latest + timeout-minutes: 60 strategy: fail-fast: false matrix: - language: [ 'javascript', 'python' ] + language: + - javascript-typescript + - python + - actions steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 - + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + # Built-in query suites: security-extended includes more rules than + # the default suite and is recommended for security-focused scanning. + queries: security-extended + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/dependabot-gcbrun.yml b/.github/workflows/dependabot-gcbrun.yml new file mode 100644 index 0000000000..f35c2b6bd8 --- /dev/null +++ b/.github/workflows/dependabot-gcbrun.yml @@ -0,0 +1,21 @@ +name: Trigger Cloud Build for Dependabot +on: + pull_request_target: + types: [opened, synchronize, reopened] + +jobs: + gcbrun: + if: github.actor == 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - name: Post /gcbrun as collaborator + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GCB_TRIGGER_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: '/gcbrun' + }) diff --git a/.github/workflows/frontend-build.yaml b/.github/workflows/frontend-build.yaml deleted file mode 100644 index f128b9aa32..0000000000 --- a/.github/workflows/frontend-build.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: Build frontend - -on: - workflow_dispatch: - push: - branches: [ "master" ] - paths: 'frontend/**' - pull_request: - branches: [ "master" ] - paths: 'frontend/**' - - -jobs: - test: -# runs-on: - runs-on: ubuntu-latest - -# strategy: -# matrix: -# node-version: [12.x, 14.x, 16.x] -# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - run: echo ${GITHUB_REF_NAME} -# - uses: actions/checkout@v3 -# - name: Use Node.js ${{ matrix.node-version }} -# uses: actions/setup-node@v3 -# with: -# node-version: ${{ matrix.node-version }} -# cache: 'npm' -# - run: npm ci -# - run: npm run build --if-present -# - run: npm test - build: - if: github.ref_name == 'master' - runs-on: ubuntu-latest - steps: - - run: echo IN MASTER ${GITHUB_REF_NAME} diff --git a/.github/workflows/set-maintenance.yml b/.github/workflows/set-maintenance.yml index 3ab480ca46..fb86a1b0e9 100644 --- a/.github/workflows/set-maintenance.yml +++ b/.github/workflows/set-maintenance.yml @@ -28,6 +28,8 @@ on: jobs: update_value: + permissions: + contents: write # The type of runner that the job will run on runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 17bafb7d79..f329dc33a4 100755 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ api/api.current.graphql **/*.env **/.venv venv +**/lib64 +**/pyvenv.cfg # Linting **/.mypy_cache/ @@ -42,6 +44,7 @@ scanner/logs # IDE Files .idea/ .vscode/ +*.code-workspace # all dist directories **/dist diff --git a/api/.env.example b/api/.env.example index ba0d411df7..d55a990ee9 100644 --- a/api/.env.example +++ b/api/.env.example @@ -27,4 +27,4 @@ REFRESH_TOKEN_EXPIRY= SCALAR_COST= SERVICE_ACCOUNT_EMAIL= SIGN_IN_KEY= -TRACING_ENABLED= \ No newline at end of file +TRACING_ENABLED= diff --git a/api/Dockerfile b/api/Dockerfile index fe4b40ff58..aacb3cd5f2 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,7 +1,7 @@ # To build image: docker build --tag tracker-api:1.0 . # To run image: docker run --network=host --env-file ./.env tracker-api:1.0 # Build image -FROM node:20.19.5-alpine3.22 AS base +FROM node:20.20.0-alpine3.22 AS base WORKDIR /app diff --git a/api/cloudbuild.yaml b/api/cloudbuild.yaml index 5ebe7355d3..c3ee4b9bf0 100644 --- a/api/cloudbuild.yaml +++ b/api/cloudbuild.yaml @@ -16,7 +16,7 @@ steps: id: install dir: api entrypoint: npm - args: ['ci', '--no-optional'] + args: ['ci'] - name: node:20-alpine id: lint @@ -56,6 +56,16 @@ steps: entrypoint: npm args: ['run', 'compile'] + - name: node:20-alpine + id: check-src-files + dir: api + entrypoint: ash + args: + - '-c' + - | + "=== checking src directory content ===" + ls -la src + - name: node:20-alpine id: test dir: api diff --git a/api/package-lock.json b/api/package-lock.json index aadfce3f0d..b1a2a46b5c 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -9,11 +9,12 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@apollo/server": "^5.2.0", + "@apollo/server": "^5.5.0", "@as-integrations/express4": "^1.1.2", "@lingui/core": "^4.13.0", + "accesscontrol": "^2.2.1", "arango-tools": "^0.6.0", - "arangojs": "^8.0.0", + "arangojs": "^10.2.2", "bcryptjs": "^2.4.3", "body-parser": "^1.20.4", "compression": "^1.8.1", @@ -47,40 +48,28 @@ "@babel/core": "^7.16.7", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.8", - "@jest/test-sequencer": "^27.4.6", + "@jest/test-sequencer": "^30.3.0", "@lingui/cli": "^5.4.1", "@lingui/macro": "^4.13.0", "babel-core": "^7.0.0-bridge.0", - "babel-jest": "^27.4.6", + "babel-jest": "^30.3.0", "babel-plugin-macros": "^3.1.0", "babel-polyfill": "^6.26.0", - "eslint": "^7.32.0", + "eslint": "^8.57.1", "eslint-config-prettier": "^8.3.0", - "eslint-config-standard": "^16.0.3", + "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jest": "^24.7.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^5.2.0", - "jest": "^27.4.7", + "eslint-plugin-jest": "^29.15.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-promise": "^6.6.0", + "jest": "^30.3.0", "jest-fetch-mock": "^3.0.3", - "jest-matcher-utils": "^27.4.6", + "jest-matcher-utils": "^30.3.0", + "nodemon": "^3.1.11", "prettier": "^2.5.1", "supertest": "^7.0.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@apollo/cache-control-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@apollo/cache-control-types/-/cache-control-types-1.0.3.tgz", @@ -90,10 +79,9 @@ } }, "node_modules/@apollo/server": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@apollo/server/-/server-5.2.0.tgz", - "integrity": "sha512-OEAl5bwVitkvVkmZlgWksSnQ10FUr6q2qJMdkexs83lsvOGmd/y81X5LoETmKZux8UiQsy/A/xzP00b8hTHH/w==", - "license": "MIT", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@apollo/server/-/server-5.5.0.tgz", + "integrity": "sha512-vWtodBOK/SZwBTJzItECOmLfL8E8pn/IdvP7pnxN5g2tny9iW4+9sxdajE798wV1H2+PYp/rRcl/soSHIBKMPw==", "dependencies": { "@apollo/cache-control-types": "^1.0.3", "@apollo/server-gateway-interface": "^2.0.0", @@ -107,7 +95,8 @@ "@apollo/utils.withrequired": "^3.0.0", "@graphql-tools/schema": "^10.0.0", "async-retry": "^1.2.1", - "body-parser": "^2.2.0", + "body-parser": "^2.2.2", + "content-type": "^1.0.5", "cors": "^2.8.5", "finalhandler": "^2.1.0", "loglevel": "^1.6.8", @@ -216,9 +205,9 @@ } }, "node_modules/@apollo/server/node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -227,7 +216,7 @@ "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.0", + "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, @@ -240,9 +229,9 @@ } }, "node_modules/@apollo/server/node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -495,12 +484,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -509,30 +498,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz", - "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -554,15 +543,15 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", - "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "dependencies": { - "@babel/parser": "^7.26.0", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -595,13 +584,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -715,6 +704,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", @@ -740,27 +738,27 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -782,9 +780,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "engines": { "node": ">=6.9.0" @@ -875,9 +873,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -899,27 +897,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -949,12 +933,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -1318,6 +1302,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", @@ -1342,6 +1341,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -1445,12 +1459,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -2106,41 +2120,41 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -2156,6 +2170,37 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.3", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", @@ -2581,30 +2626,66 @@ "node": ">=18" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2616,6 +2697,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -2628,6 +2721,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@graphql-tools/merge": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.1.6.tgz", @@ -2689,23 +2791,38 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true }, "node_modules/@ioredis/commands": { @@ -2714,27 +2831,6 @@ "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", "optional": true }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -2857,336 +2953,250 @@ } }, "node_modules/@jest/console": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.6.tgz", - "integrity": "sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.3.0.tgz", + "integrity": "sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "30.3.0", "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", + "chalk": "^4.1.2", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jest/core": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.3.0.tgz", + "integrity": "sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/console": "30.3.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.3.0", + "jest-config": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-resolve-dependencies": "30.3.0", + "jest-runner": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "jest-watcher": "30.3.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0" }, + "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": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jest/core/node_modules/jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" }, "engines": { - "node": ">=7.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@jest/core/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/@jest/console/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@jest/diff-sequences": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", + "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", "dev": true, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@jest/environment": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz", + "integrity": "sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-mock": "30.3.0" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/core": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.7.tgz", - "integrity": "sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg==", + "node_modules/@jest/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==", "dev": true, "dependencies": { - "@jest/console": "^27.4.6", - "@jest/reporters": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.7", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-resolve-dependencies": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "jest-watcher": "^27.4.6", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "expect": "30.3.0", + "jest-snapshot": "30.3.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jest/expect-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", + "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@jest/get-type": "30.1.0" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz", + "integrity": "sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==", + "dev": true, + "dependencies": { + "@jest/types": "30.3.0", + "@sinonjs/fake-timers": "^15.0.0", + "@types/node": "*", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/core/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/core/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/environment": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz", - "integrity": "sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg==", + "node_modules/@jest/globals": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz", + "integrity": "sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6" + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/types": "30.3.0", + "jest-mock": "30.3.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/fake-timers": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz", - "integrity": "sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A==", + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.6.tgz", - "integrity": "sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/types": "^27.4.2", - "expect": "^27.4.6" + "jest-regex-util": "30.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.6.tgz", - "integrity": "sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.3.0.tgz", + "integrity": "sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", + "@jest/console": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", + "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "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" @@ -3197,62 +3207,86 @@ } } }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "balanced-match": "^1.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=8" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jest/reporters/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "@isaacs/cliui": "^8.0.2" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jest/reporters/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=7.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@jest/reporters/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@jest/reporters/node_modules/slash": { @@ -3264,27 +3298,6 @@ "node": ">=8" } }, - "node_modules/@jest/reporters/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -3298,301 +3311,189 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "node_modules/@jest/snapshot-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz", + "integrity": "sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==", "dev": true, "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/source-map/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/test-result": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.6.tgz", - "integrity": "sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.3.0.tgz", + "integrity": "sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==", "dev": true, "dependencies": { - "@jest/console": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@jest/console": "30.3.0", + "@jest/types": "30.3.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/test-sequencer": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz", - "integrity": "sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.3.0.tgz", + "integrity": "sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==", "dev": true, "dependencies": { - "@jest/test-result": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-runtime": "^27.4.6" + "@jest/test-result": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" } }, "node_modules/@jest/transform": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.6.tgz", - "integrity": "sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz", + "integrity": "sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", + "@babel/core": "^7.27.4", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", + "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.3.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "pirates": "^4.0.7", "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "write-file-atomic": "^5.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jest/types": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@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": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jest/types/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@sinclair/typebox": "^0.34.0" }, "engines": { - "node": ">=7.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@jest/types/node_modules/@sinclair/typebox": { + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", "dev": true }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jest/transform/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jest/transform/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -3748,6 +3649,27 @@ "node": ">=20.0.0" } }, + "node_modules/@lingui/cli/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@lingui/cli/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/@lingui/cli/node_modules/chokidar": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", @@ -3808,15 +3730,15 @@ } }, "node_modules/@lingui/cli/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3998,61 +3920,12 @@ "node": ">=16.0.0" } }, - "node_modules/@lingui/macro/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@lingui/macro/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/@lingui/macro/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@lingui/macro/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@lingui/macro/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/@lingui/macro/node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -4079,15 +3952,6 @@ } } }, - "node_modules/@lingui/macro/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@lingui/macro/node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -4100,18 +3964,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@lingui/macro/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@lingui/message-utils": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-4.13.0.tgz", @@ -4149,6 +4001,18 @@ "moo": "^0.5.1" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -4214,6 +4078,28 @@ "@noble/hashes": "^1.1.5" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -4276,45 +4162,41 @@ "license": "MIT" }, "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", + "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^3.0.1" } }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, - "engines": { - "node": ">= 6" + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@types/babel__core": { - "version": "7.1.17", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.17.tgz", - "integrity": "sha512-6zzkezS9QEIL8yCBvXWxPTJPNuMeECJVxSOhxNY/jfq9LxOTHivaYTqr37n9LknWWRTIkzqH2UilS5QFvfa90A==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -4348,19 +4230,10 @@ "@babel/types": "^7.3.0" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/istanbul-lib-report": { @@ -4373,20 +4246,14 @@ } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -4399,9 +4266,12 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "node_modules/@types/node": { - "version": "16.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", - "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", + "dependencies": { + "undici-types": "~6.21.0" + } }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4409,22 +4279,16 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, - "node_modules/@types/prettier": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", - "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==", - "dev": true - }, "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -4436,72 +4300,67 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz", - "integrity": "sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", + "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.31.1", - "@typescript-eslint/types": "4.31.1", - "@typescript-eslint/typescript-estree": "4.31.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@typescript-eslint/tsconfig-utils": "^8.57.2", + "@typescript-eslint/types": "^8.57.2", + "debug": "^4.4.3" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", + "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz", - "integrity": "sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", + "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.31.1", - "@typescript-eslint/visitor-keys": "4.31.1" - }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.1.tgz", - "integrity": "sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", + "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -4509,40 +4368,73 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz", - "integrity": "sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", + "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.31.1", - "@typescript-eslint/visitor-keys": "4.31.1", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@typescript-eslint/project-service": "8.57.2", + "@typescript-eslint/tsconfig-utils": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -4550,23 +4442,314 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/utils": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", + "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz", - "integrity": "sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", + "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.31.1", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "8.57.2", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@whatwg-node/promise-helpers": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz", @@ -4579,12 +4762,6 @@ "node": ">=16.0.0" } }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, "node_modules/accept-language": { "version": "3.0.18", "resolved": "https://registry.npmjs.org/accept-language/-/accept-language-3.0.18.tgz", @@ -4616,10 +4793,19 @@ "node": ">= 0.6" } }, + "node_modules/accesscontrol": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/accesscontrol/-/accesscontrol-2.2.1.tgz", + "integrity": "sha512-52EvFk/J9EF+w4mYQoKnOTkEMj01R1U5n2fc1dai6x1xkgOks3DGkx01qQL2cKFxGmE4Tn1krAU3jJA9L1NMkg==", + "license": "MIT", + "dependencies": { + "notation": "^1.3.6" + } + }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -4628,16 +4814,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -4647,31 +4823,10 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -4684,15 +4839,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -4718,21 +4864,24 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -4800,18 +4949,22 @@ } }, "node_modules/arangojs": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-8.0.0.tgz", - "integrity": "sha512-VjeWxbS18c65Wu6Pr/d5/kW0Chn6ftIfUAzCmG3wUUe8OrRRalSgL6e1+5iY9apocbECo6wTK3kr2goXfLHB+A==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-10.2.2.tgz", + "integrity": "sha512-3Xllq5inTGjros0mBP9NFxrIW8Di0ldtFurLdrXy5z4NDVJPyJtnwUiiGrMPY21NuVu53wUDE23YN50jnX4epw==", "dependencies": { - "@types/node": ">=14", - "multi-part": "^4.0.0", - "path-browserify": "^1.0.1", - "x3-linkedlist": "1.2.0", - "xhr": "^2.4.1" + "@types/node": "^20.11.26" }, "engines": { - "node": ">=14" + "node": ">=20" + }, + "peerDependencies": { + "undici": ">=5.21.0" + }, + "peerDependenciesMeta": { + "undici": { + "optional": true + } } }, "node_modules/argparse": { @@ -4848,15 +5001,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/array.prototype.flat": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", @@ -4907,15 +5051,6 @@ "node": ">=6" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/async-retry": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", @@ -4945,13 +5080,13 @@ } }, "node_modules/axios": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.1.tgz", - "integrity": "sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" } }, "node_modules/babel-core": { @@ -4964,83 +5099,24 @@ } }, "node_modules/babel-jest": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.6.tgz", - "integrity": "sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz", + "integrity": "sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==", "dev": true, "dependencies": { - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "@jest/transform": "30.3.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "@babel/core": "^7.11.0 || ^8.0.0-0" } }, "node_modules/babel-jest/node_modules/slash": { @@ -5052,18 +5128,6 @@ "node": ">=8" } }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", @@ -5074,34 +5138,31 @@ } }, "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.3.0.tgz", + "integrity": "sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==", "dev": true, "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "@types/babel__core": "^7.20.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/babel-plugin-macros": { @@ -5184,42 +5245,45 @@ "dev": true }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "node_modules/babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.3.0.tgz", + "integrity": "sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" + "babel-plugin-jest-hoist": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "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" } }, "node_modules/babel-runtime": { @@ -5369,12 +5433,6 @@ "node": ">=8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "node_modules/browserslist": { "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", @@ -5451,6 +5509,39 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/builtins": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/builtins/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -5543,17 +5634,40 @@ ] }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/char-regex": { @@ -5570,7 +5684,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", "dev": true, - "optional": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -5592,7 +5705,6 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "optional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -5601,15 +5713,24 @@ } }, "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } }, "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", "dev": true }, "node_modules/cli-cursor": { @@ -5649,14 +5770,17 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/clone": { @@ -5693,7 +5817,7 @@ "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "engines": { "iojs": ">= 1.0.0", @@ -5701,24 +5825,27 @@ } }, "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "node_modules/colors": { @@ -6008,44 +6135,6 @@ "node": ">= 8" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/dataloader": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz", @@ -6078,17 +6167,19 @@ } } }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } }, "node_modules/deep-is": { "version": "0.1.4", @@ -6097,9 +6188,9 @@ "dev": true }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6196,27 +6287,6 @@ "wrappy": "1" } }, - "node_modules/diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -6234,27 +6304,6 @@ "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/dotenv": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", @@ -6311,12 +6360,12 @@ "dev": true }, "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sindresorhus/emittery?sponsor=1" @@ -6337,18 +6386,6 @@ "node": ">= 0.8" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6512,163 +6549,97 @@ "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-compat-utils/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-config-prettier": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", @@ -6682,9 +6653,9 @@ } }, "node_modules/eslint-config-standard": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", - "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", "dev": true, "funding": [ { @@ -6700,11 +6671,14 @@ "url": "https://feross.org/support" } ], + "engines": { + "node": ">=12.0.0" + }, "peerDependencies": { - "eslint": "^7.12.1", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.2.1 || ^5.0.0" + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" } }, "node_modules/eslint-import-resolver-node": { @@ -6815,23 +6789,25 @@ "node": ">=4" } }, - "node_modules/eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" }, "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "eslint": ">=4.19.1" + "eslint": ">=8" } }, "node_modules/eslint-plugin-import": { @@ -6889,169 +6865,148 @@ "dev": true }, "node_modules/eslint-plugin-jest": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.7.0.tgz", - "integrity": "sha512-wUxdF2bAZiYSKBclsUMrYHH6WxiBreNjyDxbRv345TIvPeoCEgPNEn3Sa+ZrSqsf1Dl9SqqSREXMHExlMMu1DA==", + "version": "29.15.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.1.tgz", + "integrity": "sha512-6BjyErCQauz3zfJvzLw/kAez2lf4LEpbHLvWBfEcG4EI0ZiRSwjoH2uZulMouU8kRkBH+S0rhqn11IhTvxKgKw==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "^4.0.1" + "@typescript-eslint/utils": "^8.0.0" }, "engines": { - "node": ">=10" + "node": "^20.12.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": ">= 4", - "eslint": ">=5" + "@typescript-eslint/eslint-plugin": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "jest": "*", + "typescript": ">=4.8.4 <7.0.0" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { "optional": true + }, + "jest": { + "optional": true + }, + "typescript": { + "optional": true } } }, - "node_modules/eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "node_modules/eslint-plugin-n": { + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", "dev": true, "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.5.0", + "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", + "ignore": "^5.2.4", + "is-builtin-module": "^3.2.1", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" }, "engines": { - "node": ">=8.10.0" + "node": ">=16.0.0" }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "node_modules/eslint-plugin-node/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", - "integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==", - "dev": true, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "funding": { + "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { - "eslint": "^7.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" + "eslint": ">=7.0.0" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "type-fest": "^0.20.2" }, "engines": { - "node": ">=6" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/eslint-plugin-n/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/eslint-plugin-n/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/eslint-plugin-promise": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", + "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, "node_modules/eslint/node_modules/escape-string-regexp": { @@ -7066,62 +7021,69 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "type-fest": "^0.20.2" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">=8" + "node": ">=10.13.0" } }, - "node_modules/eslint/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "type-fest": "^0.20.2" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=8" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, "engines": { "node": ">=10" }, @@ -7129,27 +7091,63 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -7166,9 +7164,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -7177,15 +7175,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -7198,19 +7187,10 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -7257,28 +7237,30 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "dev": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/expect": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.6.tgz", - "integrity": "sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6" + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/express": { @@ -7395,22 +7377,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -7420,7 +7386,7 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fast-safe-stringify": { @@ -7439,9 +7405,9 @@ } }, "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "dependencies": { "bser": "2.1.1" @@ -7459,22 +7425,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", - "dependencies": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -7549,15 +7499,15 @@ } }, "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -7682,9 +7632,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -7703,12 +7653,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -7799,6 +7743,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -7849,44 +7805,6 @@ "node": ">=4" } }, - "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -7904,6 +7822,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/graphql": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", @@ -8109,18 +8033,6 @@ "node": ">=0.10.0" } }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -8147,33 +8059,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -8198,6 +8083,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, "funding": [ { "type": "github", @@ -8214,14 +8100,21 @@ ] }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "engines": { "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -8248,9 +8141,9 @@ } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -8396,6 +8289,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -8408,12 +8316,15 @@ } }, "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8523,6 +8434,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -8535,12 +8455,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -8623,12 +8537,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -8684,42 +8592,54 @@ } }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "semver": "^7.5.4" }, "engines": { - "node": ">=8" + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", + "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/istanbul-lib-report/node_modules/has-flag": { @@ -8732,20 +8652,32 @@ } }, "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "dependencies": { - "semver": "^6.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8759,32 +8691,23 @@ } }, "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "istanbul-lib-coverage": "^3.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/istanbul-reports": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", - "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -8815,20 +8738,21 @@ } }, "node_modules/jest": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.7.tgz", - "integrity": "sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.3.0.tgz", + "integrity": "sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==", "dev": true, "dependencies": { - "@jest/core": "^27.4.7", - "import-local": "^3.0.2", - "jest-cli": "^27.4.7" + "@jest/core": "30.3.0", + "@jest/types": "30.3.0", + "import-local": "^3.2.0", + "jest-cli": "30.3.0" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "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" @@ -8840,152 +8764,111 @@ } }, "node_modules/jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.3.0.tgz", + "integrity": "sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "execa": "^5.0.0", - "throat": "^6.0.1" + "execa": "^5.1.1", + "jest-util": "30.3.0", + "p-limit": "^3.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-circus": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.6.tgz", - "integrity": "sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ==", + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-circus": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.3.0.tgz", + "integrity": "sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "p-limit": "^3.1.0", + "pretty-format": "30.3.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-circus/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { "node": ">=8" } }, "node_modules/jest-cli": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.7.tgz", - "integrity": "sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw==", - "dev": true, - "dependencies": { - "@jest/core": "^27.4.7", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.4.7", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "prompts": "^2.0.1", - "yargs": "^16.2.0" + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.3.0.tgz", + "integrity": "sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==", + "dev": true, + "dependencies": { + "@jest/core": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "yargs": "^17.7.2" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "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" @@ -8996,21 +8879,6 @@ } } }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-cli/node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -9023,132 +8891,80 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-cli/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "pretty-format": "30.3.0" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-config": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.7.tgz", - "integrity": "sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.4.6", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.6", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.6", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", - "slash": "^3.0.0" + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz", + "integrity": "sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.3.0", + "@jest/types": "30.3.0", + "babel-jest": "30.3.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-circus": "30.3.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-runner": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "parse-json": "^5.2.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "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 } } }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "balanced-match": "^1.0.0" } }, "node_modules/jest-config/node_modules/camelcase": { @@ -9163,64 +8979,94 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-config/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=10" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-config/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-config/node_modules/jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" }, "engines": { - "node": ">=7.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/jest-config/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-config/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-config/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", + "node_modules/jest-config/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/jest-config/node_modules/slash": { @@ -9232,1197 +9078,591 @@ "node": ">=8" } }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-diff": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.6.tgz", - "integrity": "sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==", + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" + "detect-newline": "^3.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-each": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.3.0.tgz", + "integrity": "sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "jest-util": "30.3.0", + "pretty-format": "30.3.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-environment-node": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.3.0.tgz", + "integrity": "sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-mock": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0" }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-environment-node/node_modules/jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" }, "engines": { - "node": ">=7.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-fetch-mock": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", + "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "cross-fetch": "^3.0.4", + "promise-polyfill": "^8.1.3" } }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-haste-map": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz", + "integrity": "sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "30.3.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", + "picomatch": "^4.0.3", + "walker": "^1.0.8" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.3.0.tgz", + "integrity": "sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==", "dev": true, "dependencies": { - "detect-newline": "^3.0.0" + "@jest/get-type": "30.1.0", + "pretty-format": "30.3.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-each": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.6.tgz", - "integrity": "sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA==", + "node_modules/jest-matcher-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", + "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6" + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.3.0", + "pretty-format": "30.3.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-message-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", + "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.3.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-message-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-mock": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", + "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-util": "30.3.0" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-environment-jsdom": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz", - "integrity": "sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/jest-environment-node": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.6.tgz", - "integrity": "sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ==", + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-fetch-mock": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", - "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "node_modules/jest-resolve": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.3.0.tgz", + "integrity": "sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==", "dev": true, "dependencies": { - "cross-fetch": "^3.0.4", - "promise-polyfill": "^8.1.3" + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", + "node_modules/jest-resolve-dependencies": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.3.0.tgz", + "integrity": "sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==", "dev": true, + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.3.0" + }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-haste-map": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.6.tgz", - "integrity": "sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ==", + "node_modules/jest-resolve/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-jasmine2": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz", - "integrity": "sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw==", + "node_modules/jest-resolve/node_modules/jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "throat": "^6.0.1" + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-jasmine2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-resolve/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-runner": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.3.0.tgz", + "integrity": "sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/console": "30.3.0", + "@jest/environment": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-leak-detector": "30.3.0", + "jest-message-util": "30.3.0", + "jest-resolve": "30.3.0", + "jest-runtime": "30.3.0", + "jest-util": "30.3.0", + "jest-watcher": "30.3.0", + "jest-worker": "30.3.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-jasmine2/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/jest-jasmine2/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/jest-jasmine2/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "node_modules/jest-runtime": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.3.0.tgz", + "integrity": "sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==", + "dev": true, + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/globals": "30.3.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-leak-detector": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz", - "integrity": "sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA==", + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "dependencies": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "balanced-match": "^1.0.0" } }, - "node_modules/jest-matcher-utils": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz", - "integrity": "sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA==", + "node_modules/jest-runtime/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-runtime/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@isaacs/cliui": "^8.0.2" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-runtime/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/jest-runtime/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-runtime/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/jest-snapshot": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz", + "integrity": "sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "pretty-format": "30.3.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/jest-message-util": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz", - "integrity": "sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA==", + "node_modules/jest-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", + "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz", - "integrity": "sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.6.tgz", - "integrity": "sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz", - "integrity": "sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.6.tgz", - "integrity": "sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg==", - "dev": true, - "dependencies": { - "@jest/console": "^27.4.6", - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-haste-map": "^27.4.6", - "jest-leak-detector": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.6.tgz", - "integrity": "sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/globals": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.6.tgz", - "integrity": "sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", - "natural-compare": "^1.4.0", - "pretty-format": "^27.4.6", - "semver": "^7.3.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", - "dev": true, - "dependencies": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "license": "MIT", + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -10453,32 +9693,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -10492,53 +9706,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/jest-validate/node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", @@ -10577,126 +9744,39 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-validate/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-validate/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-watcher": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.6.tgz", - "integrity": "sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.3.0.tgz", + "integrity": "sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==", "dev": true, "dependencies": { - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.4.2", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.3.0", + "string-length": "^4.0.2" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-worker": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz", - "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz", + "integrity": "sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==", "dev": true, "dependencies": { "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.3.0", "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "supports-color": "^8.1.1" }, "engines": { - "node": ">= 10.13.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-worker/node_modules/has-flag": { @@ -10755,80 +9835,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jsdom/node_modules/form-data": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", - "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", @@ -10943,15 +9949,6 @@ "node": ">=0.10.0" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -10990,19 +9987,7 @@ }, "engines": { "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true + } }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -11077,12 +10062,6 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -11099,76 +10078,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/loglevel": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", @@ -11276,15 +10185,6 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -11327,18 +10227,6 @@ "node": ">= 0.6" } }, - "node_modules/mime-kind": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mime-kind/-/mime-kind-4.0.0.tgz", - "integrity": "sha512-qQvglvSpS5mABi30beNFd+uHKtKkxD3dxAmhi2e589XKx+WfVqhg5i5P5LBcVgwwv3BiDpNMBWrHqU+JexW4aA==", - "dependencies": { - "file-type": "^16.5.4", - "mime-types": "^2.1.24" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", @@ -11368,9 +10256,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -11413,18 +10301,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/multi-part": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multi-part/-/multi-part-4.0.0.tgz", - "integrity": "sha512-YT/CS0PAe62kT8EoQXcQj8yIcSu18HhYv0s6ShdAFsoFly3oV5QaxODnkj0u7zH0/RFyH47cdcMVpcGXliEFVA==", - "dependencies": { - "mime-kind": "^4.0.0", - "multi-part-lite": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/multi-part-lite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/multi-part-lite/-/multi-part-lite-1.0.0.tgz", @@ -11433,6 +10309,21 @@ "node": ">=8.3.0" } }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, "node_modules/nats": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/nats/-/nats-2.18.0.tgz", @@ -11530,7 +10421,7 @@ "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, "node_modules/node-releases": { @@ -11539,6 +10430,48 @@ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, + "node_modules/nodemon": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -11548,6 +10481,12 @@ "node": ">=0.10.0" } }, + "node_modules/notation": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/notation/-/notation-1.3.6.tgz", + "integrity": "sha512-DIuJmrP/Gg1DcXKaApsqcjsJD6jEccqKSfmU3BUx/f1GHsMiTJh70cERwYc64tOmTRTARCeMwkqNNzjh3AHhiw==", + "license": "MIT" + }, "node_modules/notifications-node-client": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/notifications-node-client/-/notifications-node-client-8.2.1.tgz", @@ -11573,12 +10512,6 @@ "node": ">=8" } }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -11705,9 +10638,9 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { "deep-is": "^0.1.3", @@ -11715,7 +10648,7 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -11744,76 +10677,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -11909,12 +10772,6 @@ "node": ">=0.10.0" } }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -11924,11 +10781,6 @@ "node": ">= 0.8" } }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -11990,10 +10842,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==" }, "node_modules/path-type": { "version": "4.0.0", @@ -12004,18 +10855,6 @@ "node": ">=8" } }, - "node_modules/peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -12023,11 +10862,10 @@ "dev": true }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.6" }, @@ -12045,9 +10883,9 @@ } }, "node_modules/pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, "engines": { "node": ">= 6" @@ -12148,19 +10986,37 @@ } }, "node_modules/pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/pretty-format/node_modules/@sinclair/typebox": { + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", + "dev": true + }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -12181,34 +11037,12 @@ "node": ">= 0.6.0" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/promise-polyfill": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.0.tgz", "integrity": "sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g==", "dev": true }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -12223,9 +11057,12 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "engines": { + "node": ">=10" + } }, "node_modules/pseudolocale": { "version": "2.1.0", @@ -12251,11 +11088,12 @@ "node": ">=14" } }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" }, "node_modules/punycode": { "version": "2.1.1", @@ -12266,11 +11104,26 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", - "license": "BSD-3-Clause", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dependencies": { "side-channel": "^1.1.0" }, @@ -12281,12 +11134,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -12345,15 +11192,16 @@ } }, "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -12363,21 +11211,6 @@ "node": ">= 6" } }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/readdirp": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", @@ -12447,18 +11280,6 @@ "@babel/runtime": "^7.8.4" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", @@ -12506,35 +11327,27 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12561,13 +11374,13 @@ "node": ">=8" } }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, "node_modules/restore-cursor": { @@ -12649,18 +11462,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -12897,71 +11698,41 @@ "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", "dev": true }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { + "node_modules/simple-update-notifier": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "semver": "^7.5.3" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=10" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=6" } }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -12993,7 +11764,7 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "node_modules/stable": { @@ -13002,9 +11773,9 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" @@ -13013,15 +11784,6 @@ "node": ">=10" } }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", @@ -13040,6 +11802,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -13048,6 +11811,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -13077,14 +11841,14 @@ } }, "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" @@ -13187,22 +11951,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/superagent": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.1.tgz", @@ -13276,99 +12024,31 @@ "node": ">=4" } }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" + "@pkgr/core": "^0.2.9" }, "engines": { - "node": ">=8" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/synckit" } }, "node_modules/test-exclude": { @@ -13391,11 +12071,50 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/tmpl": { "version": "1.0.5", @@ -13458,56 +12177,26 @@ "node": ">=0.6" } }, - "node_modules/token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" + "node": ">=18.12" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "typescript": ">=4.8.4" } }, "node_modules/tsconfig-paths": { @@ -13549,27 +12238,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -13635,15 +12303,6 @@ "node": ">= 0.4" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -13674,6 +12333,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -13723,11 +12394,45 @@ "node": ">= 0.8" } }, - "node_modules/unraw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", - "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==" - }, + "node_modules/unraw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", + "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==" + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -13767,16 +12472,6 @@ "punycode": "^2.1.0" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/url-slug": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/url-slug/-/url-slug-3.0.2.tgz", @@ -13785,7 +12480,8 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "node_modules/utils-merge": { "version": "1.0.1", @@ -13804,34 +12500,25 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^2.0.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true }, "node_modules/v8flags": { "version": "3.2.0", @@ -13862,27 +12549,6 @@ "node": ">= 0.8" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -13909,49 +12575,11 @@ "defaults": "^1.0.3" } }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, "node_modules/whatwg-fetch": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -14048,72 +12676,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -14121,36 +12683,28 @@ "dev": true }, "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "node": ">=14" }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/x3-linkedlist": { @@ -14172,18 +12726,6 @@ "xtend": "^4.0.0" } }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -14216,44 +12758,46 @@ } }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } }, "dependencies": { - "@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "@apollo/cache-control-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@apollo/cache-control-types/-/cache-control-types-1.0.3.tgz", @@ -14261,9 +12805,9 @@ "requires": {} }, "@apollo/server": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@apollo/server/-/server-5.2.0.tgz", - "integrity": "sha512-OEAl5bwVitkvVkmZlgWksSnQ10FUr6q2qJMdkexs83lsvOGmd/y81X5LoETmKZux8UiQsy/A/xzP00b8hTHH/w==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@apollo/server/-/server-5.5.0.tgz", + "integrity": "sha512-vWtodBOK/SZwBTJzItECOmLfL8E8pn/IdvP7pnxN5g2tny9iW4+9sxdajE798wV1H2+PYp/rRcl/soSHIBKMPw==", "requires": { "@apollo/cache-control-types": "^1.0.3", "@apollo/server-gateway-interface": "^2.0.0", @@ -14277,7 +12821,8 @@ "@apollo/utils.withrequired": "^3.0.0", "@graphql-tools/schema": "^10.0.0", "async-retry": "^1.2.1", - "body-parser": "^2.2.0", + "body-parser": "^2.2.2", + "content-type": "^1.0.5", "cors": "^2.8.5", "finalhandler": "^2.1.0", "loglevel": "^1.6.8", @@ -14333,9 +12878,9 @@ } }, "body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "requires": { "bytes": "^3.1.2", "content-type": "^1.0.5", @@ -14343,15 +12888,15 @@ "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.0", + "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -14521,38 +13066,38 @@ } }, "@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "@babel/compat-data": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz", - "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true }, "@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -14569,15 +13114,15 @@ } }, "@babel/generator": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", - "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { - "@babel/parser": "^7.26.0", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, @@ -14601,13 +13146,13 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "requires": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -14696,6 +13241,12 @@ "@babel/types": "^7.23.0" } }, + "@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true + }, "@babel/helper-hoist-variables": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", @@ -14715,24 +13266,24 @@ } }, "@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "requires": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" } }, "@babel/helper-optimise-call-expression": { @@ -14745,9 +13296,9 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true }, "@babel/helper-remap-async-to-generator": { @@ -14814,9 +13365,9 @@ "dev": true }, "@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true }, "@babel/helper-wrap-function": { @@ -14832,24 +13383,13 @@ } }, "@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "requires": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - } - }, - "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/node": { @@ -14867,12 +13407,12 @@ } }, "@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "requires": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" } }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -15107,6 +13647,15 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.28.6" + } + }, "@babel/plugin-syntax-import-meta": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", @@ -15125,6 +13674,15 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.28.6" + } + }, "@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -15198,12 +13756,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-arrow-functions": { @@ -15644,35 +14202,35 @@ } }, "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "requires": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" } }, "@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.27.1", @@ -15685,6 +14243,37 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "dev": true, + "optional": true, + "requires": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, + "@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, "@esbuild/aix-ppc64": { "version": "0.25.3", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", @@ -15860,32 +14449,62 @@ "dev": true, "optional": true }, + "@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.4.3" + } + }, + "@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true + }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, + "js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -15894,6 +14513,12 @@ } } }, + "@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true + }, "@graphql-tools/merge": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.1.6.tgz", @@ -15931,20 +14556,26 @@ "requires": {} }, "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" } }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "@ioredis/commands": { @@ -15953,21 +14584,6 @@ "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", "optional": true }, - "@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true - }, - "@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "requires": { - "@isaacs/balanced-match": "^4.0.1" - } - }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -16053,170 +14669,80 @@ "dev": true }, "@jest/console": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.6.tgz", - "integrity": "sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.3.0.tgz", + "integrity": "sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "30.3.0", "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", + "chalk": "^4.1.2", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", "slash": "^3.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, "@jest/core": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.7.tgz", - "integrity": "sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.3.0.tgz", + "integrity": "sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==", "dev": true, "requires": { - "@jest/console": "^27.4.6", - "@jest/reporters": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", + "@jest/console": "30.3.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.7", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-resolve-dependencies": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "jest-watcher": "^27.4.6", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.3.0", + "jest-config": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-resolve-dependencies": "30.3.0", + "jest-runner": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "jest-watcher": "30.3.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "^27.4.6" + "pretty-format": "30.3.0" } }, "slash": { @@ -16224,148 +14750,182 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, + "@jest/diff-sequences": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", + "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", + "dev": true + }, "@jest/environment": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz", - "integrity": "sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz", + "integrity": "sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==", "dev": true, "requires": { - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", - "jest-mock": "^27.4.6" + "jest-mock": "30.3.0" + } + }, + "@jest/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==", + "dev": true, + "requires": { + "expect": "30.3.0", + "jest-snapshot": "30.3.0" + } + }, + "@jest/expect-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", + "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", + "dev": true, + "requires": { + "@jest/get-type": "30.1.0" } }, "@jest/fake-timers": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz", - "integrity": "sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz", + "integrity": "sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "@sinonjs/fake-timers": "^8.0.1", + "@jest/types": "30.3.0", + "@sinonjs/fake-timers": "^15.0.0", "@types/node": "*", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" } }, + "@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true + }, "@jest/globals": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.6.tgz", - "integrity": "sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz", + "integrity": "sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==", + "dev": true, + "requires": { + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/types": "30.3.0", + "jest-mock": "30.3.0" + } + }, + "@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", "dev": true, "requires": { - "@jest/environment": "^27.4.6", - "@jest/types": "^27.4.2", - "expect": "^27.4.6" + "@types/node": "*", + "jest-regex-util": "30.0.1" } }, "@jest/reporters": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.6.tgz", - "integrity": "sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.3.0.tgz", + "integrity": "sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", + "@jest/console": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-instrument": "^6.0.0", "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", + "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "balanced-match": "^1.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "requires": { - "color-name": "~1.1.4" + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.2" + } + }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -16378,110 +14938,87 @@ "@sinclair/typebox": "^0.27.8" } }, + "@jest/snapshot-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz", + "integrity": "sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==", + "dev": true, + "requires": { + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + } + }, "@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" } }, "@jest/test-result": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.6.tgz", - "integrity": "sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.3.0.tgz", + "integrity": "sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==", "dev": true, "requires": { - "@jest/console": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@jest/console": "30.3.0", + "@jest/types": "30.3.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" } }, "@jest/test-sequencer": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz", - "integrity": "sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.3.0.tgz", + "integrity": "sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==", "dev": true, "requires": { - "@jest/test-result": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-runtime": "^27.4.6" + "@jest/test-result": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } } }, "@jest/transform": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.6.tgz", - "integrity": "sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz", + "integrity": "sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", + "@babel/core": "^7.27.4", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", + "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.3.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "pirates": "^4.0.7", "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "write-file-atomic": "^5.0.1" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, "slash": { @@ -16489,96 +15026,58 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@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": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, "requires": { - "color-name": "~1.1.4" + "@sinclair/typebox": "^0.34.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "@sinclair/typebox": { + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, "@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "requires": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, @@ -16588,22 +15087,16 @@ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true }, - "@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true - }, "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", @@ -16705,6 +15198,21 @@ "js-sha256": "^0.10.1" } }, + "balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true + }, + "brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "requires": { + "balanced-match": "^4.0.2" + } + }, "chokidar": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", @@ -16748,12 +15256,12 @@ } }, "minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "requires": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" } }, "source-map": { @@ -16896,46 +15404,12 @@ "lodash.get": "^4.4.2" } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -16944,15 +15418,9 @@ "requires": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + } }, "js-yaml": { "version": "4.1.1", @@ -16962,15 +15430,6 @@ "requires": { "argparse": "^2.0.1" } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -17002,6 +15461,18 @@ "moo": "^0.5.1" } }, + "@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "optional": true, + "requires": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -17050,6 +15521,19 @@ "@noble/hashes": "^1.1.5" } }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -17111,42 +15595,41 @@ "dev": true }, "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", + "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^3.0.1" } }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true + "@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "optional": true, + "requires": { + "tslib": "^2.4.0" + } }, "@types/babel__core": { - "version": "7.1.17", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.17.tgz", - "integrity": "sha512-6zzkezS9QEIL8yCBvXWxPTJPNuMeECJVxSOhxNY/jfq9LxOTHivaYTqr37n9LknWWRTIkzqH2UilS5QFvfa90A==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -17180,19 +15663,10 @@ "@babel/types": "^7.3.0" } }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "@types/istanbul-lib-report": { @@ -17205,20 +15679,14 @@ } }, "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "requires": { "@types/istanbul-lib-report": "*" } }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -17231,9 +15699,12 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "@types/node": { - "version": "16.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", - "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" + "version": "20.19.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", + "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==", + "requires": { + "undici-types": "~6.21.0" + } }, "@types/parse-json": { "version": "4.0.0", @@ -17241,22 +15712,16 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, - "@types/prettier": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.3.tgz", - "integrity": "sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w==", - "dev": true - }, "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -17268,83 +15733,261 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, - "@typescript-eslint/experimental-utils": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz", - "integrity": "sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q==", + "@typescript-eslint/project-service": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", + "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", "dev": true, "requires": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.31.1", - "@typescript-eslint/types": "4.31.1", - "@typescript-eslint/typescript-estree": "4.31.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - } + "@typescript-eslint/tsconfig-utils": "^8.57.2", + "@typescript-eslint/types": "^8.57.2", + "debug": "^4.4.3" } }, "@typescript-eslint/scope-manager": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz", - "integrity": "sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", + "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.31.1", - "@typescript-eslint/visitor-keys": "4.31.1" + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2" } }, + "@typescript-eslint/tsconfig-utils": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", + "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", + "dev": true, + "requires": {} + }, "@typescript-eslint/types": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.1.tgz", - "integrity": "sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", + "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz", - "integrity": "sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", + "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.31.1", - "@typescript-eslint/visitor-keys": "4.31.1", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@typescript-eslint/project-service": "8.57.2", + "@typescript-eslint/tsconfig-utils": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true + }, + "brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "balanced-match": "^4.0.2" } + }, + "minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "requires": { + "brace-expansion": "^5.0.2" + } + }, + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true } } }, + "@typescript-eslint/utils": { + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", + "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.2" + } + }, "@typescript-eslint/visitor-keys": { - "version": "4.31.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz", - "integrity": "sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ==", + "version": "8.57.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", + "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.57.2", + "eslint-visitor-keys": "^5.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true + } + } + }, + "@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true + }, + "@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", "dev": true, + "optional": true, "requires": { - "@typescript-eslint/types": "4.31.1", - "eslint-visitor-keys": "^2.0.0" + "@napi-rs/wasm-runtime": "^0.2.11" } }, + "@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "dev": true, + "optional": true + }, + "@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "dev": true, + "optional": true + }, "@whatwg-node/promise-helpers": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz", @@ -17353,12 +15996,6 @@ "tslib": "^2.6.3" } }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, "accept-language": { "version": "3.0.18", "resolved": "https://registry.npmjs.org/accept-language/-/accept-language-3.0.18.tgz", @@ -17384,22 +16021,20 @@ } } }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, + "accesscontrol": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/accesscontrol/-/accesscontrol-2.2.1.tgz", + "integrity": "sha512-52EvFk/J9EF+w4mYQoKnOTkEMj01R1U5n2fc1dai6x1xkgOks3DGkx01qQL2cKFxGmE4Tn1krAU3jJA9L1NMkg==", "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "notation": "^1.3.6" } }, + "acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -17407,25 +16042,10 @@ "dev": true, "requires": {} }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -17434,12 +16054,6 @@ "uri-js": "^4.2.2" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -17456,18 +16070,18 @@ "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -17522,15 +16136,11 @@ } }, "arangojs": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-8.0.0.tgz", - "integrity": "sha512-VjeWxbS18c65Wu6Pr/d5/kW0Chn6ftIfUAzCmG3wUUe8OrRRalSgL6e1+5iY9apocbECo6wTK3kr2goXfLHB+A==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-10.2.2.tgz", + "integrity": "sha512-3Xllq5inTGjros0mBP9NFxrIW8Di0ldtFurLdrXy5z4NDVJPyJtnwUiiGrMPY21NuVu53wUDE23YN50jnX4epw==", "requires": { - "@types/node": ">=14", - "multi-part": "^4.0.0", - "path-browserify": "^1.0.1", - "x3-linkedlist": "1.2.0", - "xhr": "^2.4.1" + "@types/node": "^20.11.26" } }, "argparse": { @@ -17560,12 +16170,6 @@ "is-string": "^1.0.7" } }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, "array.prototype.flat": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", @@ -17601,12 +16205,6 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-2.0.2.tgz", "integrity": "sha512-9sBQUQZMKFKcO/C3Bo6Rx4CQany0R0UeVcefNGRRdW2vbmaMOhV1sbmlXcQLcD56juLXbSGTBm0GGuvmrAF8pA==" }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, "async-retry": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", @@ -17629,13 +16227,13 @@ } }, "axios": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.1.tgz", - "integrity": "sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "requires": { - "follow-redirects": "^1.15.6", + "follow-redirects": "^1.15.11", "form-data": "4.0.4", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" } }, "babel-core": { @@ -17646,75 +16244,25 @@ "requires": {} }, "babel-jest": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.6.tgz", - "integrity": "sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz", + "integrity": "sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==", "dev": true, "requires": { - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "@jest/transform": "30.3.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", "slash": "^3.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -17728,28 +16276,25 @@ } }, "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.3.0.tgz", + "integrity": "sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==", "dev": true, "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "@types/babel__core": "^7.20.5" } }, "babel-plugin-macros": { @@ -17819,33 +16364,36 @@ } }, "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" } }, "babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.3.0.tgz", + "integrity": "sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" + "babel-plugin-jest-hoist": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0" } }, "babel-runtime": { @@ -17964,12 +16512,6 @@ "fill-range": "^7.1.1" } }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "browserslist": { "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", @@ -18012,6 +16554,29 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + }, + "builtins": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "dev": true, + "requires": { + "semver": "^7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true + } + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -18065,14 +16630,30 @@ "dev": true }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "char-regex": { @@ -18086,7 +16667,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", "dev": true, - "optional": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -18103,7 +16683,6 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "optional": true, "requires": { "picomatch": "^2.2.1" } @@ -18111,15 +16690,15 @@ } }, "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "dev": true }, "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", "dev": true }, "cli-cursor": { @@ -18147,13 +16726,13 @@ } }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -18182,28 +16761,28 @@ "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true }, "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "colors": { @@ -18410,40 +16989,6 @@ "which": "^2.0.1" } }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, "dataloader": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz", @@ -18463,17 +17008,12 @@ "ms": "^2.1.3" } }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "requires": {} }, "deep-is": { "version": "0.1.4", @@ -18482,9 +17022,9 @@ "dev": true }, "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true }, "defaults": { @@ -18551,21 +17091,6 @@ "wrappy": "1" } }, - "diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -18580,23 +17105,6 @@ "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, "dotenv": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", @@ -18646,9 +17154,9 @@ "dev": true }, "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true }, "emoji-regex": { @@ -18662,15 +17170,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -18798,206 +17297,131 @@ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "is-glob": "^4.0.3" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "type-fest": "^0.20.2" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "requires": { - "color-name": "~1.1.4" + "argparse": "^2.0.1" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "type-fest": "^0.20.2" + "p-locate": "^5.0.0" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "yocto-queue": "^0.1.0" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "p-limit": "^3.0.2" } }, "type-fest": { @@ -19008,6 +17432,23 @@ } } }, + "eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "requires": { + "semver": "^7.5.4" + }, + "dependencies": { + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true + } + } + }, "eslint-config-prettier": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", @@ -19016,9 +17457,9 @@ "requires": {} }, "eslint-config-standard": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", - "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", "dev": true, "requires": {} }, @@ -19113,14 +17554,15 @@ } } }, - "eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", "dev": true, "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" } }, "eslint-plugin-import": { @@ -19171,93 +17613,88 @@ } }, "eslint-plugin-jest": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.7.0.tgz", - "integrity": "sha512-wUxdF2bAZiYSKBclsUMrYHH6WxiBreNjyDxbRv345TIvPeoCEgPNEn3Sa+ZrSqsf1Dl9SqqSREXMHExlMMu1DA==", + "version": "29.15.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-29.15.1.tgz", + "integrity": "sha512-6BjyErCQauz3zfJvzLw/kAez2lf4LEpbHLvWBfEcG4EI0ZiRSwjoH2uZulMouU8kRkBH+S0rhqn11IhTvxKgKw==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "^4.0.1" + "@typescript-eslint/utils": "^8.0.0" } }, - "eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "eslint-plugin-n": { + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", "dev": true, "requires": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.5.0", + "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", + "ignore": "^5.2.4", + "is-builtin-module": "^3.2.1", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" }, "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } } }, "eslint-plugin-promise": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", - "integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", + "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, "requires": {} }, "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "estraverse": "^5.2.0" } }, "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -19267,20 +17704,12 @@ "dev": true }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "esrecurse": { @@ -19290,20 +17719,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -19334,22 +17755,24 @@ "strip-final-newline": "^2.0.0" } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "dev": true }, "expect": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.6.tgz", - "integrity": "sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6" + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" } }, "express": { @@ -19439,19 +17862,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -19461,7 +17871,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fast-safe-stringify": { @@ -19480,9 +17890,9 @@ } }, "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "requires": { "bser": "2.1.1" @@ -19497,16 +17907,6 @@ "flat-cache": "^3.0.4" } }, - "file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", - "requires": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - } - }, "fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -19561,15 +17961,15 @@ } }, "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==" }, "for-each": { "version": "0.3.5", @@ -19643,22 +18043,16 @@ "dev": true }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "gensync": { "version": "1.0.0-beta.2", @@ -19720,6 +18114,15 @@ "get-intrinsic": "^1.1.1" } }, + "get-tsconfig": { + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -19758,34 +18161,6 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, "gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -19797,6 +18172,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "graphql": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", @@ -19932,15 +18313,6 @@ "parse-passwd": "^1.0.0" } }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -19959,27 +18331,6 @@ "toidentifier": "~1.0.1" } }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -19997,12 +18348,19 @@ "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, "import-fresh": { @@ -20024,9 +18382,9 @@ } }, "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -20133,18 +18491,27 @@ "has-tostringtag": "^1.0.0" } }, + "is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + } + }, "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "requires": { - "has": "^1.0.3" + "hasown": "^2.0.2" } }, "is-date-object": { @@ -20215,6 +18582,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -20224,12 +18597,6 @@ "isobject": "^3.0.1" } }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -20278,12 +18645,6 @@ "which-typed-array": "^1.1.16" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -20320,537 +18681,68 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", - "requires": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" - } - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", - "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "iterall": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", - "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" - }, - "jackspeak": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", - "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", - "dev": true, - "requires": { - "@isaacs/cliui": "^8.0.2" - } - }, - "jest": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.7.tgz", - "integrity": "sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg==", - "dev": true, - "requires": { - "@jest/core": "^27.4.7", - "import-local": "^3.0.2", - "jest-cli": "^27.4.7" - } - }, - "jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "execa": "^5.0.0", - "throat": "^6.0.1" - } - }, - "jest-circus": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.6.tgz", - "integrity": "sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-cli": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.7.tgz", - "integrity": "sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw==", - "dev": true, - "requires": { - "@jest/core": "^27.4.7", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.4.7", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "requires": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" } }, - "jest-config": { - "version": "27.4.7", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.7.tgz", - "integrity": "sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw==", + "istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "requires": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.4.6", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.6", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.6", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-runner": "^27.4.6", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", - "slash": "^3.0.0" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, - "jest-diff": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.6.tgz", - "integrity": "sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==", + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.6.tgz", - "integrity": "sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "requires": { - "color-name": "~1.1.4" + "semver": "^7.5.3" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true }, "supports-color": { @@ -20864,343 +18756,198 @@ } } }, - "jest-environment-jsdom": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz", - "integrity": "sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" - } - }, - "jest-environment-node": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.6.tgz", - "integrity": "sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ==", + "istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, "requires": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.6", - "jest-util": "^27.4.2" + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" } }, - "jest-fetch-mock": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", - "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "requires": { - "cross-fetch": "^3.0.4", - "promise-polyfill": "^8.1.3" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true + "iterall": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", + "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" }, - "jest-haste-map": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.6.tgz", - "integrity": "sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ==", + "jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz", - "integrity": "sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.6", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.6", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "@isaacs/cliui": "^8.0.2" } }, - "jest-leak-detector": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz", - "integrity": "sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA==", + "jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.3.0.tgz", + "integrity": "sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==", "dev": true, "requires": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" + "@jest/core": "30.3.0", + "@jest/types": "30.3.0", + "import-local": "^3.2.0", + "jest-cli": "30.3.0" } }, - "jest-matcher-utils": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz", - "integrity": "sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA==", + "jest-changed-files": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.3.0.tgz", + "integrity": "sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==", "dev": true, "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.6" + "execa": "^5.1.1", + "jest-util": "30.3.0", + "p-limit": "^3.1.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "yocto-queue": "^0.1.0" } } } }, - "jest-message-util": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz", - "integrity": "sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA==", + "jest-circus": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.3.0.tgz", + "integrity": "sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.6", + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "p-limit": "^3.1.0", + "pretty-format": "30.3.0", + "pure-rand": "^7.0.0", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "stack-utils": "^2.0.6" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "color-name": "~1.1.4" + "yocto-queue": "^0.1.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true + } + } + }, + "jest-cli": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.3.0.tgz", + "integrity": "sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==", + "dev": true, + "requires": { + "@jest/core": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "yargs": "^17.7.2" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" } } } }, - "jest-mock": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz", - "integrity": "sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true - }, - "jest-resolve": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.6.tgz", - "integrity": "sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.6", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" + "jest-config": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz", + "integrity": "sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==", + "dev": true, + "requires": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.3.0", + "@jest/types": "30.3.0", + "babel-jest": "30.3.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-circus": "30.3.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-runner": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "parse-json": "^5.2.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "balanced-match": "^1.0.0" } }, "camelcase": { @@ -21209,49 +18956,67 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "requires": { - "color-name": "~1.1.4" + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", + "dev": true, + "requires": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" + } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, - "jest-validate": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz", - "integrity": "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ==", + "minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.6" + "brace-expansion": "^2.0.2" + } + }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "slash": { @@ -21259,178 +19024,160 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, - "jest-resolve-dependencies": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz", - "integrity": "sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw==", + "jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.6" + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" } }, - "jest-runner": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.6.tgz", - "integrity": "sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg==", + "jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "requires": { + "detect-newline": "^3.1.0" + } + }, + "jest-each": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.3.0.tgz", + "integrity": "sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==", + "dev": true, + "requires": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "jest-util": "30.3.0", + "pretty-format": "30.3.0" + } + }, + "jest-environment-node": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.3.0.tgz", + "integrity": "sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==", "dev": true, "requires": { - "@jest/console": "^27.4.6", - "@jest/environment": "^27.4.6", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.6", - "jest-environment-node": "^27.4.6", - "jest-haste-map": "^27.4.6", - "jest-leak-detector": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-resolve": "^27.4.6", - "jest-runtime": "^27.4.6", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.6", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" + "jest-mock": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" } } } }, - "jest-runtime": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.6.tgz", - "integrity": "sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.6", - "@jest/fake-timers": "^27.4.6", - "@jest/globals": "^27.4.6", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.6", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-mock": "^27.4.6", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.6", - "jest-snapshot": "^27.4.6", - "jest-util": "^27.4.2", + "jest-fetch-mock": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", + "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "dev": true, + "requires": { + "cross-fetch": "^3.0.4", + "promise-polyfill": "^8.1.3" + } + }, + "jest-haste-map": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz", + "integrity": "sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==", + "dev": true, + "requires": { + "@jest/types": "30.3.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "fsevents": "^2.3.3", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", + "picomatch": "^4.0.3", + "walker": "^1.0.8" + }, + "dependencies": { + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true + } + } + }, + "jest-leak-detector": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.3.0.tgz", + "integrity": "sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==", + "dev": true, + "requires": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.3.0" + } + }, + "jest-matcher-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", + "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", + "dev": true, + "requires": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.3.0", + "pretty-format": "30.3.0" + } + }, + "jest-message-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", + "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.3.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3", + "pretty-format": "30.3.0", "slash": "^3.0.0", - "strip-bom": "^4.0.0" + "stack-utils": "^2.0.6" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true }, "slash": { @@ -21438,180 +19185,296 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, - "jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", + "jest-mock": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", + "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", "dev": true, "requires": { + "@jest/types": "30.3.0", "@types/node": "*", - "graceful-fs": "^4.2.4" + "jest-util": "30.3.0" } }, - "jest-snapshot": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.6.tgz", - "integrity": "sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.6", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.4.6", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.6", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.6", - "jest-matcher-utils": "^27.4.6", - "jest-message-util": "^27.4.6", - "jest-util": "^27.4.2", - "natural-compare": "^1.4.0", - "pretty-format": "^27.4.6", - "semver": "^7.3.2" + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true + }, + "jest-resolve": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.3.0.tgz", + "integrity": "sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "jest-resolve-dependencies": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.3.0.tgz", + "integrity": "sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==", + "dev": true, + "requires": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.3.0" + } + }, + "jest-runner": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.3.0.tgz", + "integrity": "sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==", + "dev": true, + "requires": { + "@jest/console": "30.3.0", + "@jest/environment": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-leak-detector": "30.3.0", + "jest-message-util": "30.3.0", + "jest-resolve": "30.3.0", + "jest-runtime": "30.3.0", + "jest-util": "30.3.0", + "jest-watcher": "30.3.0", + "jest-worker": "30.3.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "dependencies": { + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "color-name": "~1.1.4" + "yocto-queue": "^0.1.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } } } }, - "jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", + "jest-runtime": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.3.0.tgz", + "integrity": "sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==", + "dev": true, + "requires": { + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/globals": "30.3.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", - "picomatch": "^2.2.3" + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "balanced-match": "^1.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "requires": { - "color-name": "~1.1.4" + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.2" + } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "jest-snapshot": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz", + "integrity": "sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "pretty-format": "30.3.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "dependencies": { + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true + } + } + }, + "jest-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", + "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", + "dev": true, + "requires": { + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "dependencies": { + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true } } }, @@ -21643,61 +19506,12 @@ "chalk": "^4.0.0" } }, - "@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", @@ -21722,99 +19536,36 @@ "dev": true } } - }, - "react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, "jest-watcher": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.6.tgz", - "integrity": "sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.3.0.tgz", + "integrity": "sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==", "dev": true, "requires": { - "@jest/test-result": "^27.4.6", - "@jest/types": "^27.4.2", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.4.2", - "string-length": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.3.0", + "string-length": "^4.0.2" } }, "jest-worker": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz", - "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz", + "integrity": "sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==", "dev": true, "requires": { "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.3.0", "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "supports-color": "^8.1.1" }, "dependencies": { "has-flag": { @@ -21860,62 +19611,6 @@ "esprima": "^4.0.0" } }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "3.0.4", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "form-data": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", - "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35" - } - } - } - }, "jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", @@ -22003,12 +19698,6 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -22040,18 +19729,6 @@ "p-locate": "^4.1.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -22125,12 +19802,6 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -22139,57 +19810,6 @@ "requires": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "loglevel": { @@ -22271,12 +19891,6 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -22302,15 +19916,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, - "mime-kind": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mime-kind/-/mime-kind-4.0.0.tgz", - "integrity": "sha512-qQvglvSpS5mABi30beNFd+uHKtKkxD3dxAmhi2e589XKx+WfVqhg5i5P5LBcVgwwv3BiDpNMBWrHqU+JexW4aA==", - "requires": { - "file-type": "^16.5.4", - "mime-types": "^2.1.24" - } - }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", @@ -22334,9 +19939,9 @@ } }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -22369,20 +19974,17 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "multi-part": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multi-part/-/multi-part-4.0.0.tgz", - "integrity": "sha512-YT/CS0PAe62kT8EoQXcQj8yIcSu18HhYv0s6ShdAFsoFly3oV5QaxODnkj0u7zH0/RFyH47cdcMVpcGXliEFVA==", - "requires": { - "mime-kind": "^4.0.0", - "multi-part-lite": "^1.0.0" - } - }, "multi-part-lite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/multi-part-lite/-/multi-part-lite-1.0.0.tgz", "integrity": "sha512-KxIRbBZZ45hoKX1ROD/19wJr0ql1bef1rE8Y1PCwD3PuNXV42pp7Wo8lEHYuAajoT4vfAFcd3rPjlkyEEyt1nw==" }, + "napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true + }, "nats": { "version": "2.18.0", "resolved": "https://registry.npmjs.org/nats/-/nats-2.18.0.tgz", @@ -22460,7 +20062,7 @@ "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, "node-releases": { @@ -22469,12 +20071,43 @@ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, + "nodemon": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true + } + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "notation": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/notation/-/notation-1.3.6.tgz", + "integrity": "sha512-DIuJmrP/Gg1DcXKaApsqcjsJD6jEccqKSfmU3BUx/f1GHsMiTJh70cERwYc64tOmTRTARCeMwkqNNzjh3AHhiw==" + }, "notifications-node-client": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/notifications-node-client/-/notifications-node-client-8.2.1.tgz", @@ -22493,12 +20126,6 @@ "path-key": "^3.0.0" } }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -22581,9 +20208,9 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "requires": { "deep-is": "^0.1.3", @@ -22591,7 +20218,7 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" } }, "ora": { @@ -22609,57 +20236,6 @@ "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "p-limit": { @@ -22729,22 +20305,11 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -22788,9 +20353,9 @@ } }, "path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==" }, "path-type": { "version": "4.0.0", @@ -22798,11 +20363,6 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==" - }, "picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -22810,9 +20370,9 @@ "dev": true }, "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true }, "pify": { @@ -22822,9 +20382,9 @@ "dev": true }, "pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true }, "pkg-dir": { @@ -22896,16 +20456,31 @@ "dev": true }, "pretty-format": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", - "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", "dev": true, "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "dependencies": { + "@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.34.0" + } + }, + "@sinclair/typebox": { + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", + "dev": true + }, "ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -22919,28 +20494,12 @@ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "promise-polyfill": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.0.tgz", "integrity": "sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g==", "dev": true }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -22951,9 +20510,9 @@ } }, "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==" }, "pseudolocale": { "version": "2.1.0", @@ -22972,10 +20531,10 @@ } } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, "punycode": { @@ -22984,20 +20543,20 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true + }, "qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "requires": { "side-channel": "^1.1.0" } }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -23031,29 +20590,22 @@ } }, "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "requires": { - "readable-stream": "^3.6.0" - } - }, "readdirp": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", @@ -23111,12 +20663,6 @@ "@babel/runtime": "^7.8.4" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, "regexpu-core": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", @@ -23157,29 +20703,18 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-cwd": { @@ -23197,10 +20732,10 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true }, "restore-cursor": { @@ -23252,15 +20787,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -23424,55 +20950,29 @@ "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", "dev": true }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { + "simple-update-notifier": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "semver": "^7.5.3" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true } } }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -23500,7 +21000,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "stable": { @@ -23509,20 +21009,12 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } } }, "standard-as-callback": { @@ -23539,6 +21031,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "requires": { "safe-buffer": "~5.2.0" }, @@ -23546,7 +21039,8 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true } } }, @@ -23561,14 +21055,14 @@ } }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "string-width-cjs": { @@ -23638,15 +21132,6 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, - "strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - } - }, "superagent": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.1.tgz", @@ -23701,81 +21186,19 @@ "has-flag": "^3.0.0" } }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" + "@pkgr/core": "^0.2.9" } }, "test-exclude": { @@ -23795,11 +21218,30 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true + "tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "requires": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "dependencies": { + "fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "requires": {} + }, + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true + } + } }, "tmpl": { "version": "1.0.5", @@ -23838,43 +21280,18 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, - "token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, - "tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "dependencies": { - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - } - } + "touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, - "requires": { - "punycode": "^2.1.1" - } + "requires": {} }, "tsconfig-paths": { "version": "3.12.0", @@ -23910,23 +21327,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -23972,15 +21372,6 @@ "is-typed-array": "^1.1.14" } }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -24000,6 +21391,17 @@ "which-boxed-primitive": "^1.0.2" } }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -24038,6 +21440,34 @@ "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==" }, + "unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "requires": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1", + "napi-postinstall": "^0.3.0" + } + }, "update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -24057,16 +21487,6 @@ "punycode": "^2.1.0" } }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "url-slug": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/url-slug/-/url-slug-3.0.2.tgz", @@ -24075,7 +21495,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "utils-merge": { "version": "1.0.1", @@ -24087,27 +21508,21 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^2.0.0" }, "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true } } @@ -24131,24 +21546,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, "walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -24175,43 +21572,11 @@ "defaults": "^1.0.3" } }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, "whatwg-fetch": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - } - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -24263,32 +21628,6 @@ "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } } }, "wrap-ansi-cjs": { @@ -24300,32 +21639,6 @@ "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } } }, "wrappy": { @@ -24335,24 +21648,23 @@ "dev": true }, "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, "requires": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } } }, - "ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, - "requires": {} - }, "x3-linkedlist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/x3-linkedlist/-/x3-linkedlist-1.2.0.tgz", @@ -24369,18 +21681,6 @@ "xtend": "^4.0.0" } }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -24404,24 +21704,30 @@ "dev": true }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true } } diff --git a/api/package.json b/api/package.json index 6af506a985..3e59de346f 100644 --- a/api/package.json +++ b/api/package.json @@ -11,6 +11,7 @@ "build": "npm run clean && babel ./src --out-dir dist/src --ignore 'src/**/*.spec.js','src/**/*.test.js' && babel index.js --out-dir dist/", "start": "node ./dist/index.js", "dev": "NODE_OPTIONS=--dns-result-order=ipv4first babel-node index.js", + "dev:watch": "nodemon --exec babel-node index.js", "clean": "rm -rf ./dist && mkdir dist", "test": "NODE_OPTIONS=--dns-result-order=ipv4first jest --testPathIgnorePatterns=.*-scan-data.* --env=node", "only": "NODE_OPTIONS=--dns-result-order=ipv4first jest", @@ -26,11 +27,12 @@ "form-data@^4.0.0": "4.0.4" }, "dependencies": { - "@apollo/server": "^5.2.0", + "@apollo/server": "^5.5.0", "@as-integrations/express4": "^1.1.2", "@lingui/core": "^4.13.0", + "accesscontrol": "^2.2.1", "arango-tools": "^0.6.0", - "arangojs": "^8.0.0", + "arangojs": "^10.2.2", "bcryptjs": "^2.4.3", "body-parser": "^1.20.4", "compression": "^1.8.1", @@ -64,23 +66,24 @@ "@babel/core": "^7.16.7", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.8", - "@jest/test-sequencer": "^27.4.6", + "@jest/test-sequencer": "^30.3.0", "@lingui/cli": "^5.4.1", "@lingui/macro": "^4.13.0", "babel-core": "^7.0.0-bridge.0", - "babel-jest": "^27.4.6", + "babel-jest": "^30.3.0", "babel-plugin-macros": "^3.1.0", "babel-polyfill": "^6.26.0", - "eslint": "^7.32.0", + "eslint": "^8.57.1", "eslint-config-prettier": "^8.3.0", - "eslint-config-standard": "^16.0.3", + "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jest": "^24.7.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^5.2.0", - "jest": "^27.4.7", + "eslint-plugin-jest": "^29.15.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-promise": "^6.6.0", + "jest": "^30.3.0", "jest-fetch-mock": "^3.0.3", - "jest-matcher-utils": "^27.4.6", + "jest-matcher-utils": "^30.3.0", + "nodemon": "^3.1.11", "prettier": "^2.5.1", "supertest": "^7.0.0" } diff --git a/api/src/__tests__/initialize-loaders.test.js b/api/src/__tests__/initialize-loaders.test.js index f4f13aced5..923f4ab5f7 100644 --- a/api/src/__tests__/initialize-loaders.test.js +++ b/api/src/__tests__/initialize-loaders.test.js @@ -1,4 +1,4 @@ -import {initializeLoaders} from '../initialize-loaders' +import { initializeLoaders } from '../initialize-loaders' describe('initializeLoaders', () => { it('returns a object with a key for each loader', () => { @@ -13,9 +13,6 @@ describe('initializeLoaders', () => { }) expect(loaders).toHaveProperty( - 'loadChartSummaryByKey', - 'loadAggregateGuidanceTagByTagId', - 'loadAggregateGuidanceTagConnectionsByTagId', 'loadDkimFailConnectionsBySumId', 'loadDmarcFailConnectionsBySumId', 'loadDmarcSummaryConnectionsByUserId', @@ -29,23 +26,7 @@ describe('initializeLoaders', () => { 'loadDomainByKey', 'loadDomainConnectionsByOrgId', 'loadDomainConnectionsByUserId', - 'loadDnsConnectionsByDomainId', - 'loadWebConnectionsByDomainId', - 'loadWebScansByWebId', - 'loadDkimGuidanceTagByTagId', - 'loadDkimGuidanceTagConnectionsByTagId', - 'loadDmarcGuidanceTagByTagId', - 'loadDmarcGuidanceTagConnectionsByTagId', - 'loadHttpsGuidanceTagByTagId', - 'loadHttpsGuidanceTagConnectionsByTagId', - 'loadSpfGuidanceTagByTagId', - 'loadSpfGuidanceTagConnectionsByTagId', - 'loadSslGuidanceTagByTagId', - 'loadSslGuidanceTagConnectionsByTagId', 'loadOrgByKey', - 'loadOrgBySlug', - 'loadOrgConnectionsByDomainId', - 'loadOrgConnectionsByUserId', 'loadUserByUserName', 'loadUserByKey', 'loadAffiliationByKey', diff --git a/api/src/access-control.js b/api/src/access-control.js new file mode 100644 index 0000000000..195bf5633f --- /dev/null +++ b/api/src/access-control.js @@ -0,0 +1,51 @@ +// Central RBAC definition using accesscontrol +// +// This file defines role-based access control (RBAC) permissions using the AccessControl library. +// +// "Own" refers to resources affiliated with the user's organization. For example, an admin can create domains +// in their affiliated organization, but not in other organizations. This ensures users only manage resources +// within their scope of affiliation. +// +// Roles: +// - user: Basic permissions for managing own CSVs, affiliations, scan requests, and viewing own organization. +// - admin: Extends user. Can manage domains, organizations, logs, tags, and affiliations within their own org. +// - owner: Extends admin. Can delete own organization and create domains. +// - super_admin: Extends owner. Can manage any resource across all organizations. +// +// For maintainability, update permissions here when adding new roles or resources. + +import AccessControl from 'accesscontrol' + +const ac = new AccessControl() + +ac.grant('user').createOwn('csv').readOwn('affiliation').createOwn('scan-request').readOwn('organization') + +ac.grant('admin') + .extend('user') + .createOwn('domain') + .updateOwn('domain', ['*', '!archived']) + .deleteOwn('domain') + .updateOwn('organization', ['*', '!externalId', '!externallyManaged']) + .readOwn('log') + .createOwn('tag') + .updateOwn('tag') + .createOwn('affiliation') + .updateOwn('affiliation') + .deleteOwn('affiliation') + +ac.grant('owner').extend('admin').deleteOwn('organization').createOwn('cvd-enrollment').updateOwn('cvd-enrollment') + +ac.grant('super_admin') + .extend('owner') + .createAny(['organization', 'domain', 'user', 'tag', 'affiliation', 'csv', 'scan-request', 'cvd-enrollment']) + .readAny(['organization', 'domain', 'user', 'tag', 'log', 'affiliation']) + .updateAny(['organization', 'domain', 'user', 'tag', 'affiliation', 'cvd-enrollment']) + .deleteAny(['organization', 'domain', 'user', 'tag', 'affiliation']) + +ac.grant('none') // no permissions — fallback for users with no org affiliation +const _can = ac.can.bind(ac) +ac.can = (role) => _can(role || 'none') + +ac.lock() + +export default ac diff --git a/api/src/additional-findings/data-source.js b/api/src/additional-findings/data-source.js new file mode 100644 index 0000000000..e466b46191 --- /dev/null +++ b/api/src/additional-findings/data-source.js @@ -0,0 +1,8 @@ +import { loadAdditionalFindingsByDomainId, loadTop25Reports } from './loaders' + +export class AdditionalFindingsDataSource { + constructor({ query, userKey, i18n, language }) { + this.getByDomainId = loadAdditionalFindingsByDomainId({ query, userKey, i18n }) + this.getTop25Reports = loadTop25Reports({ query, userKey, i18n, language }) + } +} diff --git a/api/src/additional-findings/index.js b/api/src/additional-findings/index.js index 84c283025a..efc2b38f26 100644 --- a/api/src/additional-findings/index.js +++ b/api/src/additional-findings/index.js @@ -1,2 +1,4 @@ +export * from './data-source' export * from './loaders' export * from './objects' +export * from './input' diff --git a/api/src/additional-findings/input/cvd-enrollment-options.js b/api/src/additional-findings/input/cvd-enrollment-options.js new file mode 100644 index 0000000000..6f49454873 --- /dev/null +++ b/api/src/additional-findings/input/cvd-enrollment-options.js @@ -0,0 +1,9 @@ +import { GraphQLInputObjectType } from 'graphql' +import { cvdEnrollmentFields } from '../objects/cvd-enrollment' + +export const CvdEnrollmentInputOptions = new GraphQLInputObjectType({ + name: 'CvdEnrollmenInputOptions', + description: + 'Input options for specifying CVD enrollment details, including program status and CVSS environmental requirements.', + fields: () => ({ ...cvdEnrollmentFields }), +}) diff --git a/api/src/additional-findings/input/index.js b/api/src/additional-findings/input/index.js new file mode 100644 index 0000000000..6c8ee05330 --- /dev/null +++ b/api/src/additional-findings/input/index.js @@ -0,0 +1 @@ +export * from './cvd-enrollment-options' diff --git a/api/src/additional-findings/objects/__tests__/cvd-enrollment.test.js b/api/src/additional-findings/objects/__tests__/cvd-enrollment.test.js new file mode 100644 index 0000000000..ebfced89b9 --- /dev/null +++ b/api/src/additional-findings/objects/__tests__/cvd-enrollment.test.js @@ -0,0 +1,61 @@ +import { GraphQLObjectType, GraphQLString } from 'graphql' +import { EnrollmentStatusEnums, SeverityEnum, CvdRequirementEnums } from '../../../enums' +import { cvdEnrollment } from '../cvd-enrollment' + +describe('cvdEnrollment GraphQLObjectType', () => { + it('should be an instance of GraphQLObjectType', () => { + expect(cvdEnrollment).toBeInstanceOf(GraphQLObjectType) + }) + + it('should have the correct name and description', () => { + expect(cvdEnrollment.name).toBe('CvdEnrollment') + expect(cvdEnrollment.description).toBe( + 'Represents the CVD enrollment details for a domain asset, including enrollment status and CVSS environmental requirements.', + ) + }) + + describe('fields', () => { + const fields = cvdEnrollment.getFields() + + it('should include all expected fields', () => { + expect(fields).toHaveProperty('status') + expect(fields).toHaveProperty('description') + expect(fields).toHaveProperty('maxSeverity') + expect(fields).toHaveProperty('confidentialityRequirement') + expect(fields).toHaveProperty('integrityRequirement') + expect(fields).toHaveProperty('availabilityRequirement') + }) + + it('should have correct type and description for status', () => { + expect(fields.status.type).toBe(EnrollmentStatusEnums) + expect(fields.status.description).toBe( + 'The enrollment status of the asset in the Coordinated Vulnerability Disclosure (CVD) program.', + ) + }) + + it('should have correct type and description for description', () => { + expect(fields.description.type).toBe(GraphQLString) + expect(fields.description.description).toBe('The asset description.') + }) + + it('should have correct type and description for maxSeverity', () => { + expect(fields.maxSeverity.type).toBe(SeverityEnum) + expect(fields.maxSeverity.description).toContain('qualitative rating') + }) + + it('should have correct type and description for confidentialityRequirement', () => { + expect(fields.confidentialityRequirement.type).toBe(CvdRequirementEnums) + expect(fields.confidentialityRequirement.description).toContain('Confidentiality Impact') + }) + + it('should have correct type and description for integrityRequirement', () => { + expect(fields.integrityRequirement.type).toBe(CvdRequirementEnums) + expect(fields.integrityRequirement.description).toContain('Integrity Impact') + }) + + it('should have correct type and description for availabilityRequirement', () => { + expect(fields.availabilityRequirement.type).toBe(CvdRequirementEnums) + expect(fields.availabilityRequirement.description).toContain('Availability Impact') + }) + }) +}) diff --git a/api/src/additional-findings/objects/cvd-enrollment.js b/api/src/additional-findings/objects/cvd-enrollment.js new file mode 100644 index 0000000000..4cbb0d4ca8 --- /dev/null +++ b/api/src/additional-findings/objects/cvd-enrollment.js @@ -0,0 +1,38 @@ +import { GraphQLObjectType, GraphQLString } from 'graphql' +import { EnrollmentStatusEnums, SeverityEnum, CvdRequirementEnums } from '../../enums' + +export const cvdEnrollmentFields = { + status: { + description: 'The enrollment status of the asset in the Coordinated Vulnerability Disclosure (CVD) program.', + type: EnrollmentStatusEnums, + }, + description: { + description: 'The asset description.', + type: GraphQLString, + }, + maxSeverity: { + description: + 'The qualitative rating of the maximum severity allowed on this asset. Its value is calculated from the combination of all three of the environmental requirements (CR, IR, and AR).', + type: SeverityEnum, + }, + confidentialityRequirement: { + description: + 'A CVSS environmental modifier that reweights Confidentiality Impact of a vulnerability on this asset.', + type: CvdRequirementEnums, + }, + integrityRequirement: { + description: 'A CVSS environmental modifier that reweights Integrity Impact of a vulnerability on this asset.', + type: CvdRequirementEnums, + }, + availabilityRequirement: { + description: 'A CVSS environmental modifier that reweights Availability Impact of a vulnerability on this asset.', + type: CvdRequirementEnums, + }, +} + +export const cvdEnrollment = new GraphQLObjectType({ + name: 'CvdEnrollment', + description: + 'Represents the CVD enrollment details for a domain asset, including enrollment status and CVSS environmental requirements.', + fields: () => ({ ...cvdEnrollmentFields }), +}) diff --git a/api/src/additional-findings/objects/index.js b/api/src/additional-findings/objects/index.js index 8e7bb1a5c3..18e5dd687a 100644 --- a/api/src/additional-findings/objects/index.js +++ b/api/src/additional-findings/objects/index.js @@ -1 +1,2 @@ export * from './additional-finding' +export * from './cvd-enrollment' diff --git a/api/src/additional-findings/queries/__tests__/get-top-25-reports.test.js b/api/src/additional-findings/queries/__tests__/get-top-25-reports.test.js index 398535c7cf..3ecc2ee53d 100644 --- a/api/src/additional-findings/queries/__tests__/get-top-25-reports.test.js +++ b/api/src/additional-findings/queries/__tests__/get-top-25-reports.test.js @@ -238,13 +238,10 @@ describe('given getTop25Reports', () => { superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadTop25Reports: loadTop25Reports({ - query, - userKey: user._key, - i18n, - language: 'en', - }), + dataSources: { + additionalFindings: { + getTop25Reports: loadTop25Reports({ query, userKey: user._key, i18n, language: 'en' }), + }, }, }, }) @@ -298,13 +295,10 @@ describe('given getTop25Reports', () => { superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadTop25Reports: loadTop25Reports({ - query, - userKey: user._key, - i18n, - language: 'en', - }), + dataSources: { + additionalFindings: { + getTop25Reports: loadTop25Reports({ query, userKey: user._key, i18n, language: 'en' }), + }, }, }, }) @@ -360,13 +354,10 @@ Government of Canada,GC,2`, superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadTop25Reports: loadTop25Reports({ - query, - userKey: user._key, - i18n, - language: 'en', - }), + dataSources: { + additionalFindings: { + getTop25Reports: loadTop25Reports({ query, userKey: user._key, i18n, language: 'en' }), + }, }, }, }) @@ -421,13 +412,10 @@ Government of Canada,GC,2`, superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadTop25Reports: loadTop25Reports({ - query, - userKey: user._key, - i18n, - language: 'en', - }), + dataSources: { + additionalFindings: { + getTop25Reports: loadTop25Reports({ query, userKey: user._key, i18n, language: 'en' }), + }, }, }, }) diff --git a/api/src/additional-findings/queries/get-top-25-report.js b/api/src/additional-findings/queries/get-top-25-report.js index 1925a355fa..ec770e1419 100644 --- a/api/src/additional-findings/queries/get-top-25-report.js +++ b/api/src/additional-findings/queries/get-top-25-report.js @@ -9,7 +9,7 @@ export const getTop25Reports = { { userKey, auth: { checkSuperAdmin, userRequired, verifiedRequired, superAdminRequired }, - loaders: { loadTop25Reports }, + dataSources: { additionalFindings }, language, }, ) => { @@ -19,7 +19,7 @@ export const getTop25Reports = { const isSuperAdmin = await checkSuperAdmin() superAdminRequired({ user, isSuperAdmin }) - const top25Reports = await loadTop25Reports({ ...args }) + const top25Reports = await additionalFindings.getTop25Reports({ ...args }) console.info(`User ${userKey} successfully retrieved all top 25 reports.`) diff --git a/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js b/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js index bb0d7d1839..cac682c504 100644 --- a/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js +++ b/api/src/affiliation/mutations/__tests__/invite-user-to-org.test.js @@ -10,7 +10,7 @@ import { checkPermission, userRequired, verifiedRequired, tfaRequired } from '.. import { createMutationSchema } from '../../../mutation' import { createQuerySchema } from '../../../query' import { cleanseInput } from '../../../validators' -import { loadOrgByKey } from '../../../organization/loaders' +import { loadOrgByKey, loadOrganizationNamesById } from '../../../organization/loaders' import { loadUserByKey, loadUserByUserName } from '../../../user/loaders' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -53,6 +53,18 @@ describe('invite user to org', () => { schema: dbschema, })) tokenize = jest.fn().mockReturnValue('token') + i18n = setupI18n({ + locale: 'en', + localeData: { + en: { plurals: {} }, + fr: { plurals: {} }, + }, + locales: ['en', 'fr'], + messages: { + en: englishMessages.messages, + fr: frenchMessages.messages, + }, + }) }) beforeEach(async () => { user = await collections.users.save({ @@ -67,76 +79,62 @@ describe('invite user to org', () => { afterAll(async () => { await drop() }) - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - let org - beforeEach(async () => { - org = await ( - await collections.organizations.save( - { - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, + beforeAll(() => {}) + let org + beforeEach(async () => { + org = await ( + await collections.organizations.save( + { + orgDetails: { + en: { + slug: 'treasury-board-secretariat', + acronym: 'TBS', + name: 'Treasury Board of Canada Secretariat', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + fr: { + slug: 'secretariat-conseil-tresor', + acronym: 'SCT', + name: 'Secrétariat du Conseil Trésor du Canada', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', }, }, - { returnNew: true }, - ) - ).new - }) - describe('users role is super admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'super_admin', - }) + }, + { returnNew: true }, + ) + ).new + }) + describe('users role is super admin', () => { + beforeEach(async () => { + await collections.affiliations.save({ + _from: org._id, + _to: user._id, + permission: 'super_admin', }) - describe('inviting an existing account', () => { - describe('requested role is super_admin', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) + }) + describe('inviting an existing account', () => { + describe('requested role is super_admin', () => { + let secondaryUser + beforeEach(async () => { + secondaryUser = await collections.users.save({ + displayName: 'Test Account', + userName: 'test@email.gc.ca', }) - it('returns status message', async () => { - const sendOrgInviteEmail = jest.fn() + }) + it('returns status message', async () => { + const sendOrgInviteEmail = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -157,80 +155,81 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteEmail: sendOrgInviteEmail }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully invited user to organization, and sent notification email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully invited user to organization, and sent notification email.', }, }, - } + }, + } - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - describe('requested role is admin', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteEmail).toHaveBeenCalledWith({ + user: { + _type: 'user', displayName: 'Test Account', + id: secondaryUser._key, userName: 'test@email.gc.ca', - }) + ...secondaryUser, + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', }) - it('returns status message', async () => { - const sendOrgInviteEmail = jest.fn() + }) + }) + describe('requested role is admin', () => { + let secondaryUser + beforeEach(async () => { + secondaryUser = await collections.users.save({ + displayName: 'Test Account', + userName: 'test@email.gc.ca', + }) + }) + it('returns status message', async () => { + const sendOrgInviteEmail = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -251,80 +250,81 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteEmail: sendOrgInviteEmail }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully invited user to organization, and sent notification email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully invited user to organization, and sent notification email.', }, }, - } + }, + } - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - describe('requested role is user', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteEmail).toHaveBeenCalledWith({ + user: { + _type: 'user', displayName: 'Test Account', + id: secondaryUser._key, userName: 'test@email.gc.ca', - }) + ...secondaryUser, + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', + }) + }) + }) + describe('requested role is user', () => { + let secondaryUser + beforeEach(async () => { + secondaryUser = await collections.users.save({ + displayName: 'Test Account', + userName: 'test@email.gc.ca', }) - it('returns status message', async () => { - const sendOrgInviteEmail = jest.fn() + }) + it('returns status message', async () => { + const sendOrgInviteEmail = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -345,74 +345,75 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteEmail: sendOrgInviteEmail }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully invited user to organization, and sent notification email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully invited user to organization, and sent notification email.', }, }, - } + }, + } - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteEmail).toHaveBeenCalledWith({ + user: { + _type: 'user', + displayName: 'Test Account', + id: secondaryUser._key, + userName: 'test@email.gc.ca', + ...secondaryUser, + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', }) }) }) - describe('inviting a non-existing account', () => { - describe('requested role is super_admin', () => { - it('returns status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() - const response = await graphql({ - schema, - source: ` + }) + describe('inviting a non-existing account', () => { + describe('requested role is super_admin', () => { + it('returns status message', async () => { + const sendOrgInviteCreateAccount = jest.fn() + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -433,80 +434,81 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteCreateAccount }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully sent invitation to service, and organization email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully sent invitation to service, and organization email.', }, }, - } + }, + } - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'super_admin', - }, - }) - const createAccountLink = `https://host/create-user/${token}` - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { - userName: 'test@email.gc.ca', - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) + const token = tokenize({ + parameters: { + userName: 'test@email.gc.ca', + orgId: org._id, + requestedRole: 'super_admin', + }, + }) + const createAccountLink = `https://host/create-user/${token}` + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ + user: { + userName: 'test@email.gc.ca', + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', + createAccountLink, }) }) - describe('requested role is admin', () => { - it('returns status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() + }) + describe('requested role is admin', () => { + it('returns status message', async () => { + const sendOrgInviteCreateAccount = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -527,81 +529,82 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteCreateAccount }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully sent invitation to service, and organization email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully sent invitation to service, and organization email.', }, }, - } + }, + } - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'admin', - }, - }) - const createAccountLink = `https://host/create-user/${token}` + const token = tokenize({ + parameters: { + userName: 'test@email.gc.ca', + orgId: org._id, + requestedRole: 'admin', + }, + }) + const createAccountLink = `https://host/create-user/${token}` - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { - userName: 'test@email.gc.ca', - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ + user: { + userName: 'test@email.gc.ca', + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', + createAccountLink, }) }) - describe('requested role is user', () => { - it('returns status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() + }) + describe('requested role is user', () => { + it('returns status message', async () => { + const sendOrgInviteCreateAccount = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -622,99 +625,100 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + protocol: 'https', + get: (text) => text, }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully sent invitation to service, and organization email.', - }, - }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, + loadUserByKey: loadUserByKey({ query }), + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), }, - } - - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'user', + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) - const createAccountLink = `https://host/create-user/${token}` + notify: { sendOrgInviteCreateAccount }, + validators: { cleanseInput }, + }, + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { - userName: 'test@email.gc.ca', + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully sent invitation to service, and organization email.', + }, }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) + }, + } + + const token = tokenize({ + parameters: { + userName: 'test@email.gc.ca', + orgId: org._id, + requestedRole: 'user', + }, + }) + const createAccountLink = `https://host/create-user/${token}` + + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ + user: { + userName: 'test@email.gc.ca', + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', + createAccountLink, }) }) }) }) - describe('users role is admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'admin', - }) + }) + describe('users role is admin', () => { + beforeEach(async () => { + await collections.affiliations.save({ + _from: org._id, + _to: user._id, + permission: 'admin', }) - describe('inviting an existing account', () => { - describe('requested role is admin', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) + }) + describe('inviting an existing account', () => { + describe('requested role is admin', () => { + let secondaryUser + beforeEach(async () => { + secondaryUser = await collections.users.save({ + displayName: 'Test Account', + userName: 'test@email.gc.ca', }) - it('returns status message', async () => { - const sendOrgInviteEmail = jest.fn() + }) + it('returns status message', async () => { + const sendOrgInviteEmail = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -735,80 +739,81 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteEmail: sendOrgInviteEmail }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully invited user to organization, and sent notification email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully invited user to organization, and sent notification email.', }, }, - } + }, + } - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - describe('requested role is user', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteEmail).toHaveBeenCalledWith({ + user: { + _type: 'user', displayName: 'Test Account', + id: secondaryUser._key, userName: 'test@email.gc.ca', - }) + ...secondaryUser, + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', + }) + }) + }) + describe('requested role is user', () => { + let secondaryUser + beforeEach(async () => { + secondaryUser = await collections.users.save({ + displayName: 'Test Account', + userName: 'test@email.gc.ca', }) - it('returns status message', async () => { - const sendOrgInviteEmail = jest.fn() + }) + it('returns status message', async () => { + const sendOrgInviteEmail = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -829,75 +834,76 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteEmail: sendOrgInviteEmail }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully invited user to organization, and sent notification email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully invited user to organization, and sent notification email.', }, }, - } + }, + } - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteEmail).toHaveBeenCalledWith({ + user: { + _type: 'user', + displayName: 'Test Account', + id: secondaryUser._key, + userName: 'test@email.gc.ca', + ...secondaryUser, + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', }) }) }) - describe('inviting a non-existing account', () => { - describe('requested role is admin', () => { - it('returns status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() + }) + describe('inviting a non-existing account', () => { + describe('requested role is admin', () => { + it('returns status message', async () => { + const sendOrgInviteCreateAccount = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -918,81 +924,82 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteCreateAccount }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully sent invitation to service, and organization email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully sent invitation to service, and organization email.', }, }, - } + }, + } - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'admin', - }, - }) - const createAccountLink = `https://host/create-user/${token}` + const token = tokenize({ + parameters: { + userName: 'test@email.gc.ca', + orgId: org._id, + requestedRole: 'admin', + }, + }) + const createAccountLink = `https://host/create-user/${token}` - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { - userName: 'test@email.gc.ca', - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ + user: { + userName: 'test@email.gc.ca', + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', + createAccountLink, }) }) - describe('requested role is user', () => { - it('returns status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() + }) + describe('requested role is user', () => { + it('returns status message', async () => { + const sendOrgInviteCreateAccount = jest.fn() - const response = await graphql({ - schema, - source: ` + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { @@ -1013,1142 +1020,139 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: user._key, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, + }), + tokenize, + userRequired: userRequired({ + userKey: user._key, loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, + }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, - }) + notify: { sendOrgInviteCreateAccount }, + validators: { cleanseInput }, + }, + }) - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: 'Successfully sent invitation to service, and organization email.', - }, + const expectedResponse = { + data: { + inviteUserToOrg: { + result: { + status: 'Successfully sent invitation to service, and organization email.', }, }, - } + }, + } - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'user', - }, - }) - const createAccountLink = `https://host/create-user/${token}` + const token = tokenize({ + parameters: { + userName: 'test@email.gc.ca', + orgId: org._id, + requestedRole: 'user', + }, + }) + const createAccountLink = `https://host/create-user/${token}` - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { - userName: 'test@email.gc.ca', - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) + expect(response).toEqual(expectedResponse) + expect(consoleOutput).toEqual([ + `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: treasury-board-secretariat.`, + ]) + expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ + user: { + userName: 'test@email.gc.ca', + }, + orgNameEN: 'Treasury Board of Canada Secretariat', + orgNameFR: 'Secrétariat du Conseil Trésor du Canada', + createAccountLink, }) }) }) }) }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, + }) + describe('given an unsuccessful invitation', () => { + beforeAll(async () => { + ;({ query, drop, truncate, collections, transaction } = await ensure({ + variables: { + dbname: dbNameFromFile(__filename), + username: 'root', + rootPassword: rootPass, + password: rootPass, + url, + }, + + schema: dbschema, + })) + tokenize = jest.fn().mockReturnValue('token') + i18n = setupI18n({ + locale: 'en', + localeData: { + en: { plurals: {} }, + fr: { plurals: {} }, + }, + locales: ['en', 'fr'], + messages: { + en: englishMessages.messages, + fr: frenchMessages.messages, + }, + }) + }) + beforeEach(async () => { + user = ( + await collections.users.save( + { + userName: 'test.account@istio.actually.exists', + emailValidated: true, + tfaSendMethod: 'email', }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, + { returnNew: true }, + ) + ).new + userToInvite = ( + await collections.users.save( + { + userName: 'usertoinvite@istio.actually.exists', + emailValidated: true, + tfaSendMethod: 'email', }, - }) - }) - let org - beforeEach(async () => { - org = await ( - await collections.organizations.save( - { - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }, - { returnNew: true }, - ) - ).new - }) - describe('users role is super admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'super_admin', - }) - }) - describe('inviting an existing account', () => { - describe('requested role is super_admin', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) - }) - it('returns a status message', async () => { - const sendOrgInviteEmail = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: SUPER_ADMIN - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: - "L'utilisateur a été invité avec succès à l'organisation et l'email de notification a été envoyé.", - }, - }, - }, - } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - describe('requested role is admin', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) - }) - it('returns a status message', async () => { - const sendOrgInviteEmail = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: ADMIN - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: - "L'utilisateur a été invité avec succès à l'organisation et l'email de notification a été envoyé.", - }, - }, - }, - } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - describe('requested role is user', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) - }) - it('returns a status message', async () => { - const sendOrgInviteEmail = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: - "L'utilisateur a été invité avec succès à l'organisation et l'email de notification a été envoyé.", - }, - }, - }, - } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - }) - describe('inviting a non-existing account', () => { - describe('requested role is super_admin', () => { - it('returns a status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: SUPER_ADMIN - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: "Envoi réussi de l'invitation au service, et de l'email de l'organisation.", - }, - }, - }, - } - - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'super_admin', - }, - }) - const createAccountLink = `https://host/create-user/${token}` - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { userName: 'test@email.gc.ca' }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) - }) - }) - describe('requested role is admin', () => { - it('returns a status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: ADMIN - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: "Envoi réussi de l'invitation au service, et de l'email de l'organisation.", - }, - }, - }, - } - - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'admin', - }, - }) - const createAccountLink = `https://host/create-user/${token}` - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { userName: 'test@email.gc.ca' }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) - }) - }) - describe('requested role is user', () => { - it('returns a status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: "Envoi réussi de l'invitation au service, et de l'email de l'organisation.", - }, - }, - }, - } - - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'user', - }, - }) - const createAccountLink = `https://host/create-user/${token}` - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { userName: 'test@email.gc.ca' }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) - }) - }) - }) - }) - describe('users role is admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'admin', - }) - }) - describe('inviting an existing account', () => { - describe('requested role is admin', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) - }) - it('returns a status message', async () => { - const sendOrgInviteEmail = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: ADMIN - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: - "L'utilisateur a été invité avec succès à l'organisation et l'email de notification a été envoyé.", - }, - }, - }, - } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - describe('requested role is user', () => { - let secondaryUser - beforeEach(async () => { - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) - }) - it('returns a status message', async () => { - const sendOrgInviteEmail = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteEmail: sendOrgInviteEmail }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: - "L'utilisateur a été invité avec succès à l'organisation et l'email de notification a été envoyé.", - }, - }, - }, - } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: ${secondaryUser._key} to the org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteEmail).toHaveBeenCalledWith({ - user: { - _type: 'user', - displayName: 'Test Account', - id: secondaryUser._key, - userName: 'test@email.gc.ca', - ...secondaryUser, - }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - }) - }) - }) - }) - describe('inviting a non-existing account', () => { - describe('requested role is admin', () => { - it('returns a status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: ADMIN - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: "Envoi réussi de l'invitation au service, et de l'email de l'organisation.", - }, - }, - }, - } - - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'admin', - }, - }) - const createAccountLink = `https://host/create-user/${token}` - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { userName: 'test@email.gc.ca' }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) - }) - }) - describe('requested role is user', () => { - it('returns a status message', async () => { - const sendOrgInviteCreateAccount = jest.fn() - - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: user._key, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - tokenize, - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount }, - validators: { cleanseInput }, - }, - }) - - const expectedResponse = { - data: { - inviteUserToOrg: { - result: { - status: "Envoi réussi de l'invitation au service, et de l'email de l'organisation.", - }, - }, - }, - } - - const token = tokenize({ - parameters: { - userName: 'test@email.gc.ca', - orgId: org._id, - requestedRole: 'user', - }, - }) - const createAccountLink = `https://host/create-user/${token}` - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([ - `User: ${user._key} successfully invited user: test@email.gc.ca to the service, and org: secretariat-conseil-tresor.`, - ]) - expect(sendOrgInviteCreateAccount).toHaveBeenCalledWith({ - user: { userName: 'test@email.gc.ca' }, - orgNameEN: 'Treasury Board of Canada Secretariat', - orgNameFR: 'Secrétariat du Conseil Trésor du Canada', - createAccountLink, - }) - }) - }) - }) - }) - }) - }) - describe('given an unsuccessful invitation', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections, transaction } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - tokenize = jest.fn().mockReturnValue('token') - }) - beforeEach(async () => { - user = ( - await collections.users.save( - { - userName: 'test.account@istio.actually.exists', - emailValidated: true, - tfaSendMethod: 'email', - }, - { returnNew: true }, - ) - ).new - userToInvite = ( - await collections.users.save( - { - userName: 'usertoinvite@istio.actually.exists', - emailValidated: true, - tfaSendMethod: 'email', - }, - { returnNew: true }, - ) - ).new - org = ( - await collections.organizations.save( - { - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', + { returnNew: true }, + ) + ).new + org = ( + await collections.organizations.save( + { + orgDetails: { + en: { + slug: 'treasury-board-secretariat', + acronym: 'TBS', + name: 'Treasury Board of Canada Secretariat', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', }, fr: { slug: 'secretariat-conseil-tresor', @@ -2163,271 +1167,27 @@ describe('invite user to org', () => { }, }, { returnNew: true }, - ) - ).new - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('user attempts to invite themselves', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "${user.userName}" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query, i18n }), - }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, - }, - }) - - const error = { - data: { - inviteUserToOrg: { - result: { - code: 400, - description: "Impossible de s'inviter à un org.", - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([`User: 123 attempted to invite themselves to ${org._key}.`]) - }) - }) - describe('user attempts to invite to an org that does not exist', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: USER - orgId: "${toGlobalId('organizations', 1)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, - }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, - }, - }) - - const error = { - data: { - inviteUserToOrg: { - result: { - code: 400, - description: "Impossible d'inviter un utilisateur à une organisation inconnue.", - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to 1 however there is no org associated with that id.`, - ]) - }) - }) - describe('user with undefined permission attempts to invite a user', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "test@email.gc.ca" - requestedRole: USER - orgId: "${toGlobalId('organizations', 123)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue(undefined), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, - }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, - }, - }) - - const error = { - data: { - inviteUserToOrg: { - result: { - code: 403, - description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide concernant les invitations d'utilisateurs.", - }, - }, - }, - } + ) + ).new + }) + afterEach(async () => { + await truncate() + }) + afterAll(async () => { + await drop() + }) - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: user but does not have permission to do so.`, - ]) - }) - }) - describe('user with user level permission attempts to invite a user', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + describe('user attempts to invite themselves', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { - userName: "test@email.gc.ca" + userName: "test.account@istio.actually.exists" requestedRole: USER - orgId: "${toGlobalId('organizations', 123)}" + orgId: "${toGlobalId('organizations', 1)}" } ) { result { @@ -2442,72 +1202,72 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, + rootValue: null, + contextValue: { + i18n, + request: { + language: 'fr', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + auth: { + checkPermission: jest.fn().mockReturnValue('admin'), + tokenize, + userRequired: jest.fn().mockReturnValue({ + userName: 'test.account@istio.actually.exists', + }), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadOrgByKey: { + load: jest.fn(), }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('user'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), + loadUserByKey: { + load: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, + loadUserByUserName: { + load: jest.fn(), + }, + loadOrganizationNamesById: { + load: jest.fn(), }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, }, - }) + notify: { sendOrgInviteCreateAccount: jest.fn() }, + validators: { cleanseInput }, + }, + }) - const error = { - data: { - inviteUserToOrg: { - result: { - code: 403, - description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide concernant les invitations d'utilisateurs.", - }, + const error = { + data: { + inviteUserToOrg: { + result: { + code: 400, + description: 'Unable to invite yourself to an org.', }, }, - } + }, + } - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: user but does not have permission to do so.`, - ]) - }) + expect(response).toEqual(error) + expect(consoleOutput).toEqual([`User: 123 attempted to invite themselves to 1.`]) }) - describe('user with admin level permission attempts to invite a user to super_admin permission', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + }) + describe('user attempts to invite to an org that does not exist', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { userName: "test@email.gc.ca" - requestedRole: SUPER_ADMIN - orgId: "${toGlobalId('organizations', 123)}" + requestedRole: USER + orgId: "${toGlobalId('organizations', 1)}" } ) { result { @@ -2522,246 +1282,74 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, + rootValue: null, + contextValue: { + i18n, + request: { + language: 'fr', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + auth: { + checkPermission: jest.fn().mockReturnValue('admin'), + tokenize, + userRequired: jest.fn().mockReturnValue({ + userName: 'test.account@exists.ca', + }), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadOrgByKey: { + load: jest.fn().mockReturnValue(undefined), }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), + loadUserByKey: { + load: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, + loadUserByUserName: { + load: jest.fn(), }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, - }, - }) - - const error = { - data: { - inviteUserToOrg: { - result: { - code: 403, - description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide concernant les invitations d'utilisateurs.", - }, + loadOrganizationNamesById: { + load: jest.fn(), }, }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: super_admin but does not have permission to do so.`, - ]) - }) - }) - describe('transaction error occurs', () => { - describe('when creating affiliation', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "${userToInvite.userName}" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue('trx step err'), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query, i18n }), - }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, - }, - }) - - const error = { - data: { - inviteUserToOrg: { - result: { - code: 500, - description: "Impossible d'inviter un utilisateur. Veuillez réessayer.", - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred while user: 123 attempted to invite user: ${userToInvite._key} to org: ${org.orgDetails.fr.slug}, error: trx step err`, - ]) - }) + notify: { sendOrgInviteCreateAccount: jest.fn() }, + validators: { cleanseInput }, + }, }) - describe('when committing transaction', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "${userToInvite.userName}" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue('trx commit err'), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { - sendOrgInviteCreateAccount: jest.fn(), - sendOrgInviteEmail: jest.fn(), - }, - validators: { cleanseInput }, - }, - }) - const error = { - data: { - inviteUserToOrg: { - result: { - code: 500, - description: "Impossible d'inviter un utilisateur. Veuillez réessayer.", - }, - }, + const error = { + data: { + inviteUserToOrg: { + result: { + code: 400, + description: 'Unable to invite user to unknown organization.', }, - } + }, + }, + } - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction commit error occurred while user: 123 attempted to invite user: ${userToInvite._key} to org: secretariat-conseil-tresor, error: trx commit err`, - ]) - }) - }) + expect(response).toEqual(error) + expect(consoleOutput).toEqual([ + `User: 123 attempted to invite user: test@email.gc.ca to 1 however there is no org associated with that id.`, + ]) }) }) - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('user attempts to invite themselves', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + describe('user with undefined permission attempts to invite a user', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { - userName: "test.account@istio.actually.exists" + userName: "test@email.gc.ca" requestedRole: USER - orgId: "${toGlobalId('organizations', 1)}" + orgId: "${toGlobalId('organizations', 123)}" } ) { result { @@ -2776,71 +1364,74 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, + rootValue: null, + contextValue: { + i18n, + request: { + language: 'fr', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + auth: { + checkPermission: jest.fn().mockReturnValue(undefined), + tokenize, + userRequired: jest.fn().mockReturnValue({ + userName: 'test.account@exists.ca', + }), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadOrgByKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), + loadUserByKey: { + load: jest.fn(), }, - loaders: { - loaders: { - loadOrgByKey: { - load: jest.fn(), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, - }, + loadUserByUserName: { + load: jest.fn(), + }, + loadOrganizationNamesById: { + load: jest.fn(), }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, }, - }) + notify: { sendOrgInviteCreateAccount: jest.fn() }, + validators: { cleanseInput }, + }, + }) - const error = { - data: { - inviteUserToOrg: { - result: { - code: 400, - description: 'Unable to invite yourself to an org.', - }, + const error = { + data: { + inviteUserToOrg: { + result: { + code: 403, + description: 'Permission Denied: Please contact organization admin for help with user invitations.', }, }, - } + }, + } - expect(response).toEqual(error) - expect(consoleOutput).toEqual([`User: 123 attempted to invite themselves to 1.`]) - }) + expect(response).toEqual(error) + expect(consoleOutput).toEqual([ + `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: user but does not have permission to do so.`, + ]) }) - describe('user attempts to invite to an org that does not exist', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + }) + describe('user with user level permission attempts to invite a user', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { userName: "test@email.gc.ca" requestedRole: USER - orgId: "${toGlobalId('organizations', 1)}" + orgId: "${toGlobalId('organizations', 123)}" } ) { result { @@ -2855,70 +1446,73 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, + rootValue: null, + contextValue: { + i18n, + request: { + language: 'fr', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + auth: { + checkPermission: jest.fn().mockReturnValue('user'), + tokenize, + userRequired: jest.fn().mockReturnValue({ + userName: 'test.account@exists.ca', + }), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadOrgByKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), + loadUserByKey: { + load: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, + loadUserByUserName: { + load: jest.fn(), + }, + loadOrganizationNamesById: { + load: jest.fn(), }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, }, - }) + notify: { sendOrgInviteCreateAccount: jest.fn() }, + validators: { cleanseInput }, + }, + }) - const error = { - data: { - inviteUserToOrg: { - result: { - code: 400, - description: 'Unable to invite user to unknown organization.', - }, + const error = { + data: { + inviteUserToOrg: { + result: { + code: 403, + description: 'Permission Denied: Please contact organization admin for help with user invitations.', }, }, - } + }, + } - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to 1 however there is no org associated with that id.`, - ]) - }) + expect(response).toEqual(error) + expect(consoleOutput).toEqual([ + `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: user but does not have permission to do so.`, + ]) }) - describe('user with undefined permission attempts to invite a user', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + }) + describe('user with admin level permission attempts to invite a user to super_admin permission', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { inviteUserToOrg( input: { userName: "test@email.gc.ca" - requestedRole: USER + requestedRole: SUPER_ADMIN orgId: "${toGlobalId('organizations', 123)}" } ) { @@ -2934,61 +1528,65 @@ describe('invite user to org', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, + rootValue: null, + contextValue: { + i18n, + request: { + language: 'fr', + protocol: 'https', + get: (text) => text, + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + auth: { + checkPermission: jest.fn().mockReturnValue('admin'), + tokenize, + userRequired: jest.fn().mockReturnValue({ + userName: 'test.account@exists.ca', + }), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadOrgByKey: { + load: jest.fn().mockReturnValue({ _key: 123 }), }, - query, - collections: collectionNames, - transaction, - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue(undefined), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), + loadUserByKey: { + load: jest.fn(), }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, + loadUserByUserName: { + load: jest.fn(), + }, + loadOrganizationNamesById: { + load: jest.fn(), }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, }, - }) + notify: { sendOrgInviteCreateAccount: jest.fn() }, + validators: { cleanseInput }, + }, + }) - const error = { - data: { - inviteUserToOrg: { - result: { - code: 403, - description: 'Permission Denied: Please contact organization admin for help with user invitations.', - }, + const error = { + data: { + inviteUserToOrg: { + result: { + code: 403, + description: 'Permission Denied: Please contact super admin for help with user invitations.', }, }, - } + }, + } - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: user but does not have permission to do so.`, - ]) - }) + expect(response).toEqual(error) + expect(consoleOutput).toEqual([ + `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: super_admin but does not have permission to do so.`, + ]) }) - describe('user with user level permission attempts to invite a user', () => { + }) + describe('transaction error occurs', () => { + describe('when creating affiliation', () => { it('returns an error message', async () => { const response = await graphql({ schema, @@ -2996,9 +1594,9 @@ describe('invite user to org', () => { mutation { inviteUserToOrg( input: { - userName: "test@email.gc.ca" + userName: "${userToInvite.userName}" requestedRole: USER - orgId: "${toGlobalId('organizations', 123)}" + orgId: "${toGlobalId('organizations', org._key)}" } ) { result { @@ -3023,10 +1621,13 @@ describe('invite user to org', () => { }, query, collections: collectionNames, - transaction, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue('trx step err'), + abort: jest.fn(), + }), userKey: 123, auth: { - checkPermission: jest.fn().mockReturnValue('user'), + checkPermission: jest.fn().mockReturnValue('admin'), tokenize, userRequired: jest.fn().mockReturnValue({ userName: 'test.account@exists.ca', @@ -3035,15 +1636,10 @@ describe('invite user to org', () => { tfaRequired: jest.fn(), }, loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, + loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, notify: { sendOrgInviteCreateAccount: jest.fn() }, validators: { cleanseInput }, @@ -3054,8 +1650,8 @@ describe('invite user to org', () => { data: { inviteUserToOrg: { result: { - code: 403, - description: 'Permission Denied: Please contact organization admin for help with user invitations.', + code: 500, + description: 'Unable to invite user. Please try again.', }, }, }, @@ -3063,11 +1659,11 @@ describe('invite user to org', () => { expect(response).toEqual(error) expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: user but does not have permission to do so.`, + `Transaction step error occurred while user: 123 attempted to invite user: ${userToInvite._key} to org: treasury-board-secretariat, error: trx step err`, ]) }) }) - describe('user with admin level permission attempts to invite a user to super_admin permission', () => { + describe('when committing transaction', () => { it('returns an error message', async () => { const response = await graphql({ schema, @@ -3075,9 +1671,9 @@ describe('invite user to org', () => { mutation { inviteUserToOrg( input: { - userName: "test@email.gc.ca" - requestedRole: SUPER_ADMIN - orgId: "${toGlobalId('organizations', 123)}" + userName: "${userToInvite.userName}" + requestedRole: USER + orgId: "${toGlobalId('organizations', org._key)}" } ) { result { @@ -3102,7 +1698,11 @@ describe('invite user to org', () => { }, query, collections: collectionNames, - transaction, + transaction: jest.fn().mockReturnValue({ + step: jest.fn(), + commit: jest.fn().mockRejectedValue('trx commit err'), + abort: jest.fn(), + }), userKey: 123, auth: { checkPermission: jest.fn().mockReturnValue('admin'), @@ -3114,17 +1714,15 @@ describe('invite user to org', () => { tfaRequired: jest.fn(), }, loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _key: 123 }), - }, - loadUserByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, + loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), + }, + notify: { + sendOrgInviteCreateAccount: jest.fn(), + sendOrgInviteEmail: jest.fn(), }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, validators: { cleanseInput }, }, }) @@ -3133,8 +1731,8 @@ describe('invite user to org', () => { data: { inviteUserToOrg: { result: { - code: 403, - description: 'Permission Denied: Please contact organization admin for help with user invitations.', + code: 500, + description: 'Unable to invite user. Please try again.', }, }, }, @@ -3142,168 +1740,10 @@ describe('invite user to org', () => { expect(response).toEqual(error) expect(consoleOutput).toEqual([ - `User: 123 attempted to invite user: test@email.gc.ca to org: 123 with role: super_admin but does not have permission to do so.`, + `Transaction commit error occurred while user: 123 attempted to invite user: ${userToInvite._key} to org: treasury-board-secretariat, error: trx commit err`, ]) }) }) - describe('transaction error occurs', () => { - describe('when creating affiliation', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "${userToInvite.userName}" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue('trx step err'), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { sendOrgInviteCreateAccount: jest.fn() }, - validators: { cleanseInput }, - }, - }) - - const error = { - data: { - inviteUserToOrg: { - result: { - code: 500, - description: 'Unable to invite user. Please try again.', - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred while user: 123 attempted to invite user: ${userToInvite._key} to org: treasury-board-secretariat, error: trx step err`, - ]) - }) - }) - describe('when committing transaction', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - inviteUserToOrg( - input: { - userName: "${userToInvite.userName}" - requestedRole: USER - orgId: "${toGlobalId('organizations', org._key)}" - } - ) { - result { - ... on InviteUserToOrgResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'fr', - protocol: 'https', - get: (text) => text, - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue('trx commit err'), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - tokenize, - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@exists.ca', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - notify: { - sendOrgInviteCreateAccount: jest.fn(), - sendOrgInviteEmail: jest.fn(), - }, - validators: { cleanseInput }, - }, - }) - - const error = { - data: { - inviteUserToOrg: { - result: { - code: 500, - description: 'Unable to invite user. Please try again.', - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction commit error occurred while user: 123 attempted to invite user: ${userToInvite._key} to org: treasury-board-secretariat, error: trx commit err`, - ]) - }) - }) - }) }) }) }) diff --git a/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js b/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js index c525449ca4..fc9ce588cb 100644 --- a/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js +++ b/api/src/affiliation/mutations/__tests__/request-org-affiliation.test.js @@ -10,7 +10,7 @@ import { userRequired, verifiedRequired } from '../../../auth' import { createMutationSchema } from '../../../mutation' import { createQuerySchema } from '../../../query' import { cleanseInput } from '../../../validators' -import { loadOrgByKey } from '../../../organization/loaders' +import { loadOrgByKey, loadOrganizationNamesById } from '../../../organization/loaders' import { loadUserByKey } from '../../../user/loaders' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -172,6 +172,7 @@ describe('invite user to org', () => { loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, notify: { sendInviteRequestEmail: sendInviteRequestEmail }, validators: { cleanseInput }, @@ -332,6 +333,9 @@ describe('invite user to org', () => { loadUserByKey: { load: jest.fn(), }, + loadOrganizationNamesById: { + load: jest.fn(), + }, }, notify: { sendInviteRequestEmail: jest.fn() }, validators: { cleanseInput }, @@ -406,6 +410,9 @@ describe('invite user to org', () => { loadUserByKey: { load: jest.fn(), }, + loadOrganizationNamesById: { + load: jest.fn(), + }, }, notify: { sendInviteRequestEmail: jest.fn() }, validators: { cleanseInput }, @@ -481,6 +488,9 @@ describe('invite user to org', () => { loadUserByKey: { load: jest.fn(), }, + loadOrganizationNamesById: { + load: jest.fn(), + }, }, notify: { sendInviteRequestEmail: jest.fn() }, validators: { cleanseInput }, @@ -550,6 +560,7 @@ describe('invite user to org', () => { loaders: { loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), loadUserByKey: loadUserByKey({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, notify: { sendInviteRequestEmail: jest.fn() }, validators: { cleanseInput }, @@ -604,6 +615,7 @@ describe('invite user to org', () => { loaders: { loadOrgByKey: loadOrgByKey({ query, language: i18n.locale }), loadUserByKey: loadUserByKey({ query }), + loadOrganizationNamesById: loadOrganizationNamesById({ query }), }, notify: { sendInviteRequestEmail: jest.fn() }, validators: { cleanseInput }, diff --git a/api/src/affiliation/mutations/__tests__/update-user-role.test.js b/api/src/affiliation/mutations/__tests__/update-user-role.test.js index 826ab8e17a..7d455c4e91 100644 --- a/api/src/affiliation/mutations/__tests__/update-user-role.test.js +++ b/api/src/affiliation/mutations/__tests__/update-user-role.test.js @@ -25,6 +25,12 @@ describe('update a users role', () => { const mockedWarn = (output) => consoleOutput.push(output) const mockedError = (output) => consoleOutput.push(output) + const sendRoleChangeEmail = jest.fn() + const orgNames = { + en: 'Treasury Board of Canada Secretariat', + fr: 'Secrétariat du Conseil Trésor du Canada', + } + beforeAll(async () => { console.info = mockedInfo console.warn = mockedWarn @@ -178,10 +184,12 @@ describe('update a users role', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, + notify: { sendRoleChangeEmail }, loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, }, validators: { cleanseInput, @@ -256,10 +264,12 @@ describe('update a users role', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, + notify: { sendRoleChangeEmail }, loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, }, validators: { cleanseInput, @@ -343,10 +353,12 @@ describe('update a users role', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, + notify: { sendRoleChangeEmail }, loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, }, validators: { cleanseInput, @@ -421,10 +433,12 @@ describe('update a users role', () => { verifiedRequired: verifiedRequired({ i18n }), tfaRequired: tfaRequired({ i18n }), }, + notify: { sendRoleChangeEmail }, loaders: { loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, }, validators: { cleanseInput, @@ -457,1423 +471,174 @@ describe('update a users role', () => { beforeEach(async () => { await collections.affiliations.save({ _from: org._id, - _to: user._id, - permission: 'admin', - }) - }) - describe('update user from user', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: secondaryUser._id, - permission: 'user', - }) - }) - describe('to admin', () => { - it('returns status message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', org._key)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - user { - displayName - } - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const expectedResponse = { - data: { - updateUserRole: { - result: { - status: 'User role was updated successfully.', - user: { - displayName: 'Test Account', - }, - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: ${user._key} successful updated user: ${secondaryUser._key} role to admin in org: treasury-board-secretariat.`, - ]) - expect(response).toEqual(expectedResponse) - }) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - let org, secondaryUser - beforeEach(async () => { - org = await collections.organizations.save({ - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }) - secondaryUser = await collections.users.save({ - displayName: 'Test Account', - userName: 'test@email.gc.ca', - }) - }) - describe('requesting user is a super admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'super_admin', - }) - }) - describe('update user from admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: secondaryUser._id, - permission: 'admin', - }) - }) - describe('to super admin', () => { - it('returns status message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', org._key)}" - role: SUPER_ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - user { - displayName - } - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const expectedResponse = { - data: { - updateUserRole: { - result: { - status: "Le rôle de l'utilisateur a été mis à jour avec succès.", - user: { - displayName: 'Test Account', - }, - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: ${user._key} successful updated user: ${secondaryUser._key} role to super_admin in org: treasury-board-secretariat.`, - ]) - expect(response).toEqual(expectedResponse) - }) - }) - describe('to user', () => { - it('returns status message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', org._key)}" - role: USER - } - ) { - result { - ... on UpdateUserRoleResult { - status - user { - displayName - } - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const expectedResponse = { - data: { - updateUserRole: { - result: { - status: "Le rôle de l'utilisateur a été mis à jour avec succès.", - user: { - displayName: 'Test Account', - }, - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: ${user._key} successful updated user: ${secondaryUser._key} role to user in org: treasury-board-secretariat.`, - ]) - expect(response).toEqual(expectedResponse) - }) - }) - }) - describe('update user from user', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: secondaryUser._id, - permission: 'user', - }) - }) - describe('to super admin', () => { - it('returns status message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', org._key)}" - role: SUPER_ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - user { - displayName - } - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const expectedResponse = { - data: { - updateUserRole: { - result: { - status: "Le rôle de l'utilisateur a été mis à jour avec succès.", - user: { - displayName: 'Test Account', - }, - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: ${user._key} successful updated user: ${secondaryUser._key} role to super_admin in org: treasury-board-secretariat.`, - ]) - expect(response).toEqual(expectedResponse) - }) - }) - describe('to admin', () => { - it('returns status message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', org._key)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - user { - displayName - } - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const expectedResponse = { - data: { - updateUserRole: { - result: { - status: "Le rôle de l'utilisateur a été mis à jour avec succès.", - user: { - displayName: 'Test Account', - }, - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: ${user._key} successful updated user: ${secondaryUser._key} role to admin in org: treasury-board-secretariat.`, - ]) - expect(response).toEqual(expectedResponse) - }) - }) - }) - }) - describe('requesting user is admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'admin', - }) - }) - describe('update user from user', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: secondaryUser._id, - permission: 'user', - }) - }) - describe('to admin', () => { - it('returns status message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', org._key)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - user { - displayName - } - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({ i18n }), - tfaRequired: tfaRequired({ i18n }), - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - loadUserByUserName: loadUserByUserName({ query }), - }, - validators: { - cleanseInput, - }, - }, - }) - - const expectedResponse = { - data: { - updateUserRole: { - result: { - status: "Le rôle de l'utilisateur a été mis à jour avec succès.", - user: { - displayName: 'Test Account', - }, - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: ${user._key} successful updated user: ${secondaryUser._key} role to admin in org: treasury-board-secretariat.`, - ]) - expect(response).toEqual(expectedResponse) - }) - }) - }) - }) - }) - }) - describe('given an unsuccessful update', () => { - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given an unsuccessful role update', () => { - describe('user attempts to update their own role', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test.account@istio.actually.exists" - orgId: "${toGlobalId('organizations', 123)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn(), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn(), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = { - data: { - updateUserRole: { - result: { - code: 400, - description: 'Unable to update your own role.', - }, - }, - }, - } - - expect(consoleOutput).toEqual([`User: 123 attempted to update their own role in org: 123.`]) - expect(response).toEqual(error) - }) - }) - describe('user attempts to update a user that does not exist', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "random@email.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn(), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn(), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = { - data: { - updateUserRole: { - result: { - code: 400, - description: 'Unable to update role: user unknown.', - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: 123 attempted to update a user: random@email.ca role in org: 123, however there is no user associated with that user name.`, - ]) - expect(response).toEqual(error) - }) - }) - describe('user attempts to update a users role in an org that does not exist', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 1)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn(), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = { - data: { - updateUserRole: { - result: { - code: 400, - description: 'Unable to update role: organization unknown.', - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: 123 attempted to update a user: 456 role in org: 1, however there is no org associated with that id.`, - ]) - expect(response).toEqual(error) - }) - }) - describe('requesting user permission is user', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('user'), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = { - data: { - updateUserRole: { - result: { - code: 400, - description: - 'Permission Denied: Please contact organization admin for help with user role changes.', - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: 123 attempted to update a user: 456 role in org: treasury-board-secretariat, however they do not have permission to do so.`, - ]) - expect(response).toEqual(error) - }) - }) - describe('user attempts to update a users role in an org that the requesting user does not belong to', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ count: 0 }), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue(undefined), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = { - data: { - updateUserRole: { - result: { - code: 400, - description: - 'Permission Denied: Please contact organization admin for help with user role changes.', - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: 123 attempted to update a user: 456 role in org: treasury-board-secretariat, however they do not have permission to do so.`, - ]) - expect(response).toEqual(error) - }) - }) - describe('user attempts to update a user that does not belong to the requested org', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ count: 0 }), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = { - data: { - updateUserRole: { - result: { - code: 400, - description: 'Unable to update role: user does not belong to organization.', - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: 123 attempted to update a user: 456 role in org: treasury-board-secretariat, however that user does not have an affiliation with that organization.`, - ]) - expect(response).toEqual(error) - }) - }) - describe('requesting users role is admin', () => { - describe('requested users role is super admin', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: USER - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - count: 1, - next: jest.fn().mockReturnValue({ permission: 'super_admin' }), - }), - collections: collectionNames, - transaction: jest.fn(), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = { - data: { - updateUserRole: { - result: { - code: 400, - description: - 'Permission Denied: Please contact organization admin for help with user role changes.', - }, - }, - }, - } - - expect(consoleOutput).toEqual([ - `User: 123 attempted to update a user: 456 role in org: treasury-board-secretariat, however they do not have permission to update a super_admin.`, - ]) - expect(response).toEqual(error) - }) - }) - }) - }) - describe('database error occurs', () => { - describe('when getting current affiliation', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: USER - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockRejectedValue(new Error('database error')), - collections: collectionNames, - transaction: jest.fn(), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] - - expect(consoleOutput).toEqual([ - `Database error occurred when user: 123 attempted to update a user's: 456 role, error: Error: database error`, - ]) - expect(response.errors).toEqual(error) - }) - }) - }) - describe('cursor error occur', () => { - describe('when gathering affiliation info', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: USER - } - ) { - result { - ... on UpdateUserRoleResult { - status - } - ... on AffiliationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - count: 1, - next: jest.fn().mockRejectedValue(new Error('cursor error')), - }), - collections: collectionNames, - transaction: jest.fn(), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, - }), - }, - }, - validators: { - cleanseInput, - }, - }, - }) - - const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] - - expect(consoleOutput).toEqual([ - `Cursor error occurred when user: 123 attempted to update a user's: 456 role, error: Error: cursor error`, - ]) - expect(response.errors).toEqual(error) - }) - }) - }) - describe('transaction error occurs', () => { - describe('when running transaction', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status + _to: user._id, + permission: 'admin', + }) + }) + describe('update user from user', () => { + beforeEach(async () => { + await collections.affiliations.save({ + _from: org._id, + _to: secondaryUser._id, + permission: 'user', + }) + }) + describe('to admin', () => { + it('returns status message', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + updateUserRole ( + input: { + userName: "test@email.gc.ca" + orgId: "${toGlobalId('organizations', org._key)}" + role: ADMIN } - ... on AffiliationError { - code - description + ) { + result { + ... on UpdateUserRoleResult { + status + user { + displayName + } + } + ... on AffiliationError { + code + description + } } } } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - count: 1, - next: jest.fn().mockReturnValue({ permission: 'user' }), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue('trx step error'), - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', + `, + rootValue: null, + contextValue: { + i18n, + query, + collections: collectionNames, + transaction, + userKey: user._key, + request: { ip: '127.0.0.1' }, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, + userRequired: userRequired({ + userKey: user._key, + loadUserByKey: loadUserByKey({ query }), }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + notify: { sendRoleChangeEmail }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, + validators: { + cleanseInput, }, }, - validators: { - cleanseInput, - }, - }, - }) + }) - const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] + const expectedResponse = { + data: { + updateUserRole: { + result: { + status: 'User role was updated successfully.', + user: { + displayName: 'Test Account', + }, + }, + }, + }, + } - expect(consoleOutput).toEqual([ - `Transaction step error occurred when user: 123 attempted to update a user's: 456 role, error: trx step error`, - ]) - expect(response.errors).toEqual(error) - }) - }) - describe('when committing transaction', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateUserRole ( - input: { - userName: "test@email.gc.ca" - orgId: "${toGlobalId('organizations', 123)}" - role: ADMIN - } - ) { - result { - ... on UpdateUserRoleResult { - status + expect(consoleOutput).toEqual([ + `User: ${user._key} successful updated user: ${secondaryUser._key} role to admin in org: treasury-board-secretariat.`, + ]) + expect(response).toEqual(expectedResponse) + }) + it('sends a role update notification email with correct parameters', async () => { + await graphql({ + schema, + source: ` + mutation { + updateUserRole ( + input: { + userName: "test@email.gc.ca" + orgId: "${toGlobalId('organizations', org._key)}" + role: USER } - ... on AffiliationError { - code - description + ) { + result { + ... on UpdateUserRoleResult { + status + user { + displayName + } + } + ... on AffiliationError { + code + description + } } } } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - count: 1, - next: jest.fn().mockReturnValue({ permission: 'user' }), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue('trx commit error'), - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ - userName: 'test.account@istio.actually.exists', - }), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', + `, + rootValue: null, + contextValue: { + i18n, + query, + collections: collectionNames, + transaction, + userKey: user._key, + request: { ip: '127.0.0.1' }, + auth: { + checkPermission: checkPermission({ + userKey: user._key, + query, }), - }, - loadUserByUserName: { - load: jest.fn().mockReturnValue({ - _key: 456, + userRequired: userRequired({ + userKey: user._key, + loadUserByKey: loadUserByKey({ query }), }), + verifiedRequired: verifiedRequired({ i18n }), + tfaRequired: tfaRequired({ i18n }), + }, + notify: { sendRoleChangeEmail }, + loaders: { + loadOrgByKey: loadOrgByKey({ query, language: 'en' }), + loadUserByKey: loadUserByKey({ query }), + loadUserByUserName: loadUserByUserName({ query }), + loadOrganizationNamesById: { load: jest.fn().mockResolvedValue(orgNames) }, + }, + validators: { + cleanseInput, }, }, - validators: { - cleanseInput, - }, - }, - }) - - const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] + }) - expect(consoleOutput).toEqual([ - `Transaction commit error occurred when user: 123 attempted to update a user's: 456 role, error: trx commit error`, - ]) - expect(response.errors).toEqual(error) + expect(sendRoleChangeEmail).toHaveBeenCalledWith({ + user: expect.any(Object), + newRole: 'user', + oldRole: expect.any(String), + orgNames, + }) + }) }) }) }) }) - describe('users language is set to french', () => { + }) + describe('given an unsuccessful update', () => { + describe('users language is set to english', () => { beforeAll(() => { i18n = setupI18n({ - locale: 'fr', + locale: 'en', localeData: { en: { plurals: {} }, fr: { plurals: {} }, @@ -1935,6 +700,7 @@ describe('update a users role', () => { load: jest.fn(), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, @@ -1946,7 +712,7 @@ describe('update a users role', () => { updateUserRole: { result: { code: 400, - description: 'Impossible de mettre à jour votre propre rôle.', + description: 'Unable to update your own role.', }, }, }, @@ -1997,6 +763,7 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, + notify: { sendRoleChangeEmail }, loaders: { loadOrgByKey: { load: jest.fn(), @@ -2016,7 +783,7 @@ describe('update a users role', () => { updateUserRole: { result: { code: 400, - description: 'Impossible de mettre à jour le rôle : utilisateur inconnu.', + description: 'Unable to update role: user unknown.', }, }, }, @@ -2069,6 +836,7 @@ describe('update a users role', () => { verifiedRequired: jest.fn(), tfaRequired: jest.fn(), }, + notify: { sendRoleChangeEmail }, loaders: { loadOrgByKey: { load: jest.fn().mockReturnValue(undefined), @@ -2090,7 +858,7 @@ describe('update a users role', () => { updateUserRole: { result: { code: 400, - description: 'Impossible de mettre à jour le rôle : organisation inconnue.', + description: 'Unable to update role: organization unknown.', }, }, }, @@ -2155,6 +923,7 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, @@ -2165,9 +934,9 @@ describe('update a users role', () => { data: { updateUserRole: { result: { - code: 400, + code: 403, description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur les changements de rôle des utilisateurs.", + 'Permission Denied: Please contact organization admin for help with user role changes.', }, }, }, @@ -2232,6 +1001,7 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, @@ -2242,9 +1012,9 @@ describe('update a users role', () => { data: { updateUserRole: { result: { - code: 400, + code: 403, description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur les changements de rôle des utilisateurs.", + 'Permission Denied: Please contact organization admin for help with user role changes.', }, }, }, @@ -2309,6 +1079,7 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, @@ -2320,8 +1091,7 @@ describe('update a users role', () => { updateUserRole: { result: { code: 400, - description: - "Impossible de mettre à jour le rôle : l'utilisateur n'appartient pas à l'organisation.", + description: 'Unable to update role: user does not belong to organization.', }, }, }, @@ -2333,7 +1103,6 @@ describe('update a users role', () => { expect(response).toEqual(error) }) }) - describe('requesting users role is admin', () => { describe('requested users role is super admin', () => { it('returns an error message', async () => { @@ -2391,6 +1160,7 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, @@ -2401,16 +1171,15 @@ describe('update a users role', () => { data: { updateUserRole: { result: { - code: 400, - description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur les changements de rôle des utilisateurs.", + code: 403, + description: 'Permission Denied: Please contact super admin for help with user role changes.', }, }, }, } expect(consoleOutput).toEqual([ - `User: 123 attempted to update a user: 456 role in org: treasury-board-secretariat, however they do not have permission to update a super_admin.`, + `User: 123 attempted to update a user: 456 role in org: treasury-board-secretariat, however they do not have permission to update a super_admin or assign the user role.`, ]) expect(response).toEqual(error) }) @@ -2471,15 +1240,14 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, }, }) - const error = [ - new GraphQLError(`Impossible de mettre à jour le rôle de l'utilisateur. Veuillez réessayer.`), - ] + const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] expect(consoleOutput).toEqual([ `Database error occurred when user: 123 attempted to update a user's: 456 role, error: Error: database error`, @@ -2545,15 +1313,14 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, }, }) - const error = [ - new GraphQLError(`Impossible de mettre à jour le rôle de l'utilisateur. Veuillez réessayer.`), - ] + const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] expect(consoleOutput).toEqual([ `Cursor error occurred when user: 123 attempted to update a user's: 456 role, error: Error: cursor error`, @@ -2622,15 +1389,14 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, }, }) - const error = [ - new GraphQLError(`Impossible de mettre à jour le rôle de l'utilisateur. Veuillez réessayer.`), - ] + const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] expect(consoleOutput).toEqual([ `Transaction step error occurred when user: 123 attempted to update a user's: 456 role, error: trx step error`, @@ -2698,15 +1464,14 @@ describe('update a users role', () => { }), }, }, + notify: { sendRoleChangeEmail }, validators: { cleanseInput, }, }, }) - const error = [ - new GraphQLError(`Impossible de mettre à jour le rôle de l'utilisateur. Veuillez réessayer.`), - ] + const error = [new GraphQLError(`Unable to update user's role. Please try again.`)] expect(consoleOutput).toEqual([ `Transaction commit error occurred when user: 123 attempted to update a user's: 456 role, error: trx commit error`, diff --git a/api/src/affiliation/mutations/invite-user-to-org.js b/api/src/affiliation/mutations/invite-user-to-org.js index 13641ea12e..8398c497aa 100644 --- a/api/src/affiliation/mutations/invite-user-to-org.js +++ b/api/src/affiliation/mutations/invite-user-to-org.js @@ -6,6 +6,7 @@ import { t } from '@lingui/macro' import { inviteUserToOrgUnion } from '../unions' import { logActivity } from '../../audit-logs/mutations/log-activity' import { InvitationRoleEnums } from '../../enums' +import ac from '../../access-control' export const inviteUserToOrg = new mutationWithClientMutationId({ name: 'InviteUserToOrg', @@ -45,7 +46,7 @@ able to sign-up and be assigned to that organization in one mutation.`, userKey, request: { ip }, auth: { checkPermission, tokenize, userRequired, verifiedRequired, tfaRequired }, - loaders: { loadOrgByKey, loadUserByUserName }, + loaders: { loadOrgByKey, loadUserByUserName, loadOrganizationNamesById }, notify: { sendOrgInviteCreateAccount, sendOrgInviteEmail }, validators: { cleanseInput }, }, @@ -88,11 +89,7 @@ able to sign-up and be assigned to that organization in one mutation.`, const permission = await checkPermission({ orgId: org._id }) // Only admins, owners, and super admins may invite users to an org - // Only super admins may create owners and other super admins - if ( - (['user', 'admin'].includes(requestedRole) && !['admin', 'owner', 'super_admin'].includes(permission)) || - (['super_admin', 'owner'].includes(requestedRole) && permission !== 'super_admin') - ) { + if (!ac.can(permission).createOwn('affiliation').granted) { console.warn( `User: ${userKey} attempted to invite user: ${userName} to org: ${org._key} with role: ${requestedRole} but does not have permission to do so.`, ) @@ -103,29 +100,26 @@ able to sign-up and be assigned to that organization in one mutation.`, } } - // Get org names to use in email - let orgNamesCursor - try { - orgNamesCursor = await query` - LET org = DOCUMENT(organizations, ${org._id}) - RETURN { - "orgNameEN": org.orgDetails.en.name, - "orgNameFR": org.orgDetails.fr.name, - } - ` - } catch (err) { - console.error( - `Database error occurred when user: ${userKey} attempted to invite user: ${userName} to org: ${org._key}. Error while creating cursor for retrieving organization names. error: ${err}`, + // Only super admins may create owners and other super admins + const privilegedRoles = ac.getRoles().filter((r) => ac.can(r).deleteOwn('organization').granted) + if (privilegedRoles.includes(requestedRole) && !ac.can(permission).createAny('affiliation').granted) { + console.warn( + `User: ${userKey} attempted to invite user: ${userName} to org: ${org._key} with role: ${requestedRole} but does not have permission to do so.`, ) - throw new Error(i18n._(t`Unable to invite user to organization. Please try again.`)) + return { + _type: 'error', + code: 403, + description: i18n._(t`Permission Denied: Please contact super admin for help with user invitations.`), + } } + // Get org names to use in email let orgNames try { - orgNames = await orgNamesCursor.next() + orgNames = await loadOrganizationNamesById.load(org._id) } catch (err) { console.error( - `Cursor error occurred when user: ${userKey} attempted to invite user: ${userName} to org: ${org._key}. Error while retrieving organization names. error: ${err}`, + `Error occurred when user: ${userKey} attempted to invite user: ${userName} to org: ${org._key}. Error while retrieving organization names. error: ${err}`, ) throw new Error(i18n._(t`Unable to invite user to organization. Please try again.`)) } diff --git a/api/src/affiliation/mutations/remove-user-from-org.js b/api/src/affiliation/mutations/remove-user-from-org.js index bce720cfe0..88a780090b 100644 --- a/api/src/affiliation/mutations/remove-user-from-org.js +++ b/api/src/affiliation/mutations/remove-user-from-org.js @@ -4,6 +4,7 @@ import { t } from '@lingui/macro' import { removeUserFromOrgUnion } from '../unions' import { logActivity } from '../../audit-logs/mutations/log-activity' +import ac from '../../access-control' export const removeUserFromOrg = new mutationWithClientMutationId({ name: 'RemoveUserFromOrg', @@ -117,7 +118,7 @@ export const removeUserFromOrg = new mutationWithClientMutationId({ } // Only admins, owners, and super admins can remove users - if (['admin', 'owner', 'super_admin'].includes(permission) === false) { + if (!ac.can(permission).deleteOwn('affiliation').granted) { console.warn( `User: ${userKey} attempted to remove user: ${requestedUser._key} from org: ${requestedOrg._key}, but they do not have the right permission.`, ) diff --git a/api/src/affiliation/mutations/request-org-affiliation.js b/api/src/affiliation/mutations/request-org-affiliation.js index a46806cbdc..c38b6b8161 100644 --- a/api/src/affiliation/mutations/request-org-affiliation.js +++ b/api/src/affiliation/mutations/request-org-affiliation.js @@ -35,7 +35,7 @@ export const requestOrgAffiliation = new mutationWithClientMutationId({ userKey, request: { ip }, auth: { userRequired, verifiedRequired }, - loaders: { loadOrgByKey, loadUserByKey }, + loaders: { loadOrgByKey, loadUserByKey, loadOrganizationNamesById }, notify: { sendInviteRequestEmail }, validators: { cleanseInput }, }, @@ -156,28 +156,12 @@ export const requestOrgAffiliation = new mutationWithClientMutationId({ if (orgAdmins.length > 0) { // Get org names to use in email - let orgNamesCursor - try { - orgNamesCursor = await query` - LET org = DOCUMENT(organizations, ${org._id}) - RETURN { - "orgNameEN": org.orgDetails.en.name, - "orgNameFR": org.orgDetails.fr.name, - } - ` - } catch (err) { - console.error( - `Database error occurred when user: ${userKey} attempted to request invite to org: ${org._key}. Error while creating cursor for retrieving organization names. error: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to request invite. Please try again.`)) - } let orgNames try { - orgNames = await orgNamesCursor.next() + orgNames = await loadOrganizationNamesById.load(org._id) } catch (err) { console.error( - `Cursor error occurred when user: ${userKey} attempted to request invite to org: ${org._key}. Error while retrieving organization names. error: ${err}`, + `Error occurred when user: ${userKey} attempted to request invite to org: ${org._key}. Error while retrieving organization names. error: ${err}`, ) await trx.abort() throw new Error(i18n._(t`Unable to request invite. Please try again.`)) diff --git a/api/src/affiliation/mutations/update-user-role.js b/api/src/affiliation/mutations/update-user-role.js index d54c70bea7..1f92a58a5b 100644 --- a/api/src/affiliation/mutations/update-user-role.js +++ b/api/src/affiliation/mutations/update-user-role.js @@ -6,6 +6,7 @@ import { t } from '@lingui/macro' import { RoleEnums } from '../../enums' import { updateUserRoleUnion } from '../unions' import { logActivity } from '../../audit-logs/mutations/log-activity' +import ac from '../../access-control' export const updateUserRole = new mutationWithClientMutationId({ name: 'UpdateUserRole', @@ -43,8 +44,9 @@ given organization.`, userKey, request: { ip }, auth: { checkPermission, userRequired, verifiedRequired, tfaRequired }, - loaders: { loadOrgByKey, loadUserByUserName }, + loaders: { loadOrgByKey, loadUserByUserName, loadOrganizationNamesById }, validators: { cleanseInput }, + notify: { sendRoleChangeEmail }, }, ) => { // Cleanse Input @@ -100,13 +102,13 @@ given organization.`, const permission = await checkPermission({ orgId: org._id }) // Only admins, owners, and super admins can update a user's role - if (['admin', 'owner', 'super_admin'].includes(permission) === false) { + if (!ac.can(permission).updateOwn('affiliation').granted) { console.warn( `User: ${userKey} attempted to update a user: ${requestedUser._key} role in org: ${org.slug}, however they do not have permission to do so.`, ) return { _type: 'error', - code: 400, + code: 403, description: i18n._(t`Permission Denied: Please contact organization admin for help with user role changes.`), } } @@ -150,27 +152,19 @@ given organization.`, throw new Error(i18n._(t`Unable to update user's role. Please try again.`)) } - // Only super admins can update other super admins or owners - if (['owner', 'super_admin'].includes(affiliation.permission) && permission !== 'super_admin') { - console.warn( - `User: ${userKey} attempted to update a user: ${requestedUser._key} role in org: ${org.slug}, however they do not have permission to update a ${affiliation.permission}.`, - ) - return { - _type: 'error', - code: 400, - description: i18n._(t`Permission Denied: Please contact organization admin for help with user role changes.`), - } - } - - // Only super admins can make other users super admins or owners - if (['owner', 'super_admin'].includes(role) && permission !== 'super_admin') { + // Only super admins can update or assign privileged roles (those with org-level authority) + const privilegedRoles = ac.getRoles().filter((r) => ac.can(r).deleteOwn('organization').granted) + if ( + (privilegedRoles.includes(affiliation.permission) || privilegedRoles.includes(role)) && + !ac.can(permission).updateAny('affiliation').granted + ) { console.warn( - `User: ${userKey} attempted to update a user: ${requestedUser._key} role in org: ${org.slug}, however they do not have permission to make a user a ${role}.`, + `User: ${userKey} attempted to update a user: ${requestedUser._key} role in org: ${org.slug}, however they do not have permission to update a ${affiliation.permission} or assign the ${role} role.`, ) return { _type: 'error', - code: 400, - description: i18n._(t`Permission Denied: Please contact organization admin for help with user role changes.`), + code: 403, + description: i18n._(t`Permission Denied: Please contact super admin for help with user role changes.`), } } @@ -212,6 +206,19 @@ given organization.`, throw new Error(i18n._(t`Unable to update user's role. Please try again.`)) } + // Get org names to use in email + let orgNames + try { + orgNames = await loadOrganizationNamesById.load(org._id) + } catch (err) { + console.error( + `Error occurred when user: ${userKey} attempted to update a user's: ${userName} role. Error while retrieving organization names. error: ${err}`, + ) + throw new Error(i18n._(t`Unable to update user's role. Please try again.`)) + } + + await sendRoleChangeEmail({ user: requestedUser, newRole: role, oldRole: affiliation.permission, orgNames }) + console.info(`User: ${userKey} successful updated user: ${requestedUser._key} role to ${role} in org: ${org.slug}.`) await logActivity({ transaction, diff --git a/api/src/audit-logs/data-source.js b/api/src/audit-logs/data-source.js new file mode 100644 index 0000000000..054ad8f259 --- /dev/null +++ b/api/src/audit-logs/data-source.js @@ -0,0 +1,39 @@ +import { loadAuditLogByKey, loadAuditLogsByOrgId } from './loaders' + +export class AuditLogsDataSource { + constructor({ query, userKey, cleanseInput, i18n, transaction, collections }) { + this._query = query + this._transaction = transaction + this._collections = collections + this.byKey = loadAuditLogByKey({ query, userKey, i18n }) + this.getConnectionsByOrgId = loadAuditLogsByOrgId({ query, userKey, cleanseInput, i18n }) + } + + async logActivity({ initiatedBy, action, target, reason = '' }) { + const auditLog = { + timestamp: new Date().toISOString(), + initiatedBy, + target, + action, + reason, + } + + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH auditLogs + INSERT ${auditLog} INTO auditLogs + RETURN MERGE({ id: NEW._key, _type: "auditLog" }, NEW) + `, + ) + await trx.commit() + } catch (err) { + console.error(`Transaction error occurred while attempting to log user action: ${err}`) + await trx.abort() + } + + return auditLog + } +} diff --git a/api/src/audit-logs/index.js b/api/src/audit-logs/index.js index a07660be28..b6bdbe9eea 100644 --- a/api/src/audit-logs/index.js +++ b/api/src/audit-logs/index.js @@ -1,3 +1,4 @@ +export * from './data-source' export * from './input' export * from './loaders' export * from './mutations' diff --git a/api/src/audit-logs/queries/find-audit-logs.js b/api/src/audit-logs/queries/find-audit-logs.js index 838c60a6c1..b10186c116 100644 --- a/api/src/audit-logs/queries/find-audit-logs.js +++ b/api/src/audit-logs/queries/find-audit-logs.js @@ -4,6 +4,7 @@ import { logConnection } from '../objects/log-connection' import { logOrder } from '../input/log-order' import { t } from '@lingui/macro' import { logFilters } from '../input/log-filters' +import ac from '../../access-control' export const findAuditLogs = { type: logConnection.connectionType, @@ -34,7 +35,8 @@ export const findAuditLogs = { userKey, i18n, auth: { checkPermission, userRequired, verifiedRequired }, - loaders: { loadAuditLogsByOrgId, loadOrgByKey }, + loaders: { loadOrgByKey }, + dataSources: { auditLogs }, validators: { cleanseInput }, }, ) => { @@ -47,10 +49,10 @@ export const findAuditLogs = { // Check to see if user belongs to org const permission = await checkPermission({ orgId: org?._id }) - if (['admin', 'owner', 'super_admin'].includes(permission) === false) { + if (!ac.can(permission).readOwn('log').granted) { throw new Error(i18n._(t`Cannot query audit logs on organization without admin permission or higher.`)) } - const auditLogCollection = await loadAuditLogsByOrgId({ + const auditLogCollection = await auditLogs.getConnectionsByOrgId({ ...args, orgId: org?._key, permission, diff --git a/api/src/auth/__tests__/check-domain-ownership.test.js b/api/src/auth/checks/__tests__/check-domain-ownership.test.js similarity index 98% rename from api/src/auth/__tests__/check-domain-ownership.test.js rename to api/src/auth/checks/__tests__/check-domain-ownership.test.js index 3cfc3696bd..d66f96673a 100644 --- a/api/src/auth/__tests__/check-domain-ownership.test.js +++ b/api/src/auth/checks/__tests__/check-domain-ownership.test.js @@ -1,11 +1,11 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' import { checkDomainOwnership } from '../index' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/__tests__/check-domain-permission.test.js b/api/src/auth/checks/__tests__/check-domain-permission.test.js similarity index 98% rename from api/src/auth/__tests__/check-domain-permission.test.js rename to api/src/auth/checks/__tests__/check-domain-permission.test.js index 75a39f40c7..0682857b02 100644 --- a/api/src/auth/__tests__/check-domain-permission.test.js +++ b/api/src/auth/checks/__tests__/check-domain-permission.test.js @@ -1,11 +1,11 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' import { checkDomainPermission } from '../index' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/__tests__/check-org-owner.test.js b/api/src/auth/checks/__tests__/check-org-owner.test.js similarity index 96% rename from api/src/auth/__tests__/check-org-owner.test.js rename to api/src/auth/checks/__tests__/check-org-owner.test.js index 5de1865d01..e2a97b2e87 100644 --- a/api/src/auth/__tests__/check-org-owner.test.js +++ b/api/src/auth/checks/__tests__/check-org-owner.test.js @@ -1,11 +1,11 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' import { checkOrgOwner } from '../check-org-owner' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/__tests__/check-permission.test.js b/api/src/auth/checks/__tests__/check-permission.test.js similarity index 98% rename from api/src/auth/__tests__/check-permission.test.js rename to api/src/auth/checks/__tests__/check-permission.test.js index 6ecc880c9e..73171b4092 100644 --- a/api/src/auth/__tests__/check-permission.test.js +++ b/api/src/auth/checks/__tests__/check-permission.test.js @@ -1,11 +1,11 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' import { checkPermission } from '..' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/__tests__/check-super-admin.test.js b/api/src/auth/checks/__tests__/check-super-admin.test.js similarity index 97% rename from api/src/auth/__tests__/check-super-admin.test.js rename to api/src/auth/checks/__tests__/check-super-admin.test.js index e71c2d309a..f355b27bce 100644 --- a/api/src/auth/__tests__/check-super-admin.test.js +++ b/api/src/auth/checks/__tests__/check-super-admin.test.js @@ -1,11 +1,11 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' import { checkSuperAdmin } from '../check-super-admin' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/__tests__/check-user-belongs-to-org.test.js b/api/src/auth/checks/__tests__/check-user-belongs-to-org.test.js similarity index 95% rename from api/src/auth/__tests__/check-user-belongs-to-org.test.js rename to api/src/auth/checks/__tests__/check-user-belongs-to-org.test.js index 6cc5bcad14..6956696979 100644 --- a/api/src/auth/__tests__/check-user-belongs-to-org.test.js +++ b/api/src/auth/checks/__tests__/check-user-belongs-to-org.test.js @@ -1,11 +1,11 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' import { checkUserBelongsToOrg } from '../check-user-belongs-to-org' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/__tests__/check-user-is-admin-for-user.test.js b/api/src/auth/checks/__tests__/check-user-is-admin-for-user.test.js similarity index 98% rename from api/src/auth/__tests__/check-user-is-admin-for-user.test.js rename to api/src/auth/checks/__tests__/check-user-is-admin-for-user.test.js index 5146267b56..2a14fe5334 100644 --- a/api/src/auth/__tests__/check-user-is-admin-for-user.test.js +++ b/api/src/auth/checks/__tests__/check-user-is-admin-for-user.test.js @@ -1,11 +1,11 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' import { checkUserIsAdminForUser } from '../index' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/check-domain-ownership.js b/api/src/auth/checks/check-domain-ownership.js similarity index 100% rename from api/src/auth/check-domain-ownership.js rename to api/src/auth/checks/check-domain-ownership.js diff --git a/api/src/auth/check-domain-permission.js b/api/src/auth/checks/check-domain-permission.js similarity index 100% rename from api/src/auth/check-domain-permission.js rename to api/src/auth/checks/check-domain-permission.js diff --git a/api/src/auth/check-org-owner.js b/api/src/auth/checks/check-org-owner.js similarity index 100% rename from api/src/auth/check-org-owner.js rename to api/src/auth/checks/check-org-owner.js diff --git a/api/src/auth/check-permission.js b/api/src/auth/checks/check-permission.js similarity index 100% rename from api/src/auth/check-permission.js rename to api/src/auth/checks/check-permission.js diff --git a/api/src/auth/check-super-admin.js b/api/src/auth/checks/check-super-admin.js similarity index 100% rename from api/src/auth/check-super-admin.js rename to api/src/auth/checks/check-super-admin.js diff --git a/api/src/auth/check-user-belongs-to-org.js b/api/src/auth/checks/check-user-belongs-to-org.js similarity index 100% rename from api/src/auth/check-user-belongs-to-org.js rename to api/src/auth/checks/check-user-belongs-to-org.js diff --git a/api/src/auth/check-user-is-admin-for-user.js b/api/src/auth/checks/check-user-is-admin-for-user.js similarity index 100% rename from api/src/auth/check-user-is-admin-for-user.js rename to api/src/auth/checks/check-user-is-admin-for-user.js diff --git a/api/src/auth/checks/index.js b/api/src/auth/checks/index.js new file mode 100644 index 0000000000..0aaa93dda3 --- /dev/null +++ b/api/src/auth/checks/index.js @@ -0,0 +1,7 @@ +export * from './check-domain-ownership' +export * from './check-domain-permission' +export * from './check-org-owner' +export * from './check-permission' +export * from './check-super-admin' +export * from './check-user-belongs-to-org' +export * from './check-user-is-admin-for-user' diff --git a/api/src/auth/data-source.js b/api/src/auth/data-source.js new file mode 100644 index 0000000000..67389d24b6 --- /dev/null +++ b/api/src/auth/data-source.js @@ -0,0 +1,9 @@ +import { loadPermissionByOrgId, loadDomainPermissionByDomainId, loadOrgOwnerByOrgId } from './loaders' + +export class AuthDataSource { + constructor({ query, userKey, i18n }) { + this.permissionByOrgId = loadPermissionByOrgId({ query, userKey, i18n }) + this.domainPermissionByDomainId = loadDomainPermissionByDomainId({ query, userKey, i18n }) + this.orgOwnerByOrgId = loadOrgOwnerByOrgId({ query, userKey, i18n }) + } +} diff --git a/api/src/auth/__tests__/tfa-required.test.js b/api/src/auth/guards/__tests__/tfa-required.test.js similarity index 96% rename from api/src/auth/__tests__/tfa-required.test.js rename to api/src/auth/guards/__tests__/tfa-required.test.js index 6e719eb568..c48657cef0 100644 --- a/api/src/auth/__tests__/tfa-required.test.js +++ b/api/src/auth/guards/__tests__/tfa-required.test.js @@ -1,8 +1,8 @@ import { setupI18n } from '@lingui/core' import { tfaRequired } from '../index' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' describe('given the tfaRequired function', () => { let i18n, user diff --git a/api/src/auth/__tests__/user-required.test.js b/api/src/auth/guards/__tests__/user-required.test.js similarity index 96% rename from api/src/auth/__tests__/user-required.test.js rename to api/src/auth/guards/__tests__/user-required.test.js index 24c300d331..19c4a72715 100644 --- a/api/src/auth/__tests__/user-required.test.js +++ b/api/src/auth/guards/__tests__/user-required.test.js @@ -1,12 +1,12 @@ import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../testUtilities' +import { ensureDatabase as ensure } from '../../../testUtilities' import { setupI18n } from '@lingui/core' -import { loadUserByKey, loadUserByUserName } from '../../user/loaders' +import { loadUserByKey, loadUserByUserName } from '../../../user/loaders' import { userRequired } from '../index' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' -import dbschema from '../../../database.json' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' const { DB_PASS: rootPass, DB_URL: url } = process.env diff --git a/api/src/auth/__tests__/verified-required.test.js b/api/src/auth/guards/__tests__/verified-required.test.js similarity index 96% rename from api/src/auth/__tests__/verified-required.test.js rename to api/src/auth/guards/__tests__/verified-required.test.js index 8a9d25cb5a..4ea31d45de 100644 --- a/api/src/auth/__tests__/verified-required.test.js +++ b/api/src/auth/guards/__tests__/verified-required.test.js @@ -1,8 +1,8 @@ import { setupI18n } from '@lingui/core' import { verifiedRequired } from '../index' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' describe('given the verifiedRequired function', () => { let i18n, user diff --git a/api/src/auth/guards/index.js b/api/src/auth/guards/index.js new file mode 100644 index 0000000000..5a21e03fae --- /dev/null +++ b/api/src/auth/guards/index.js @@ -0,0 +1,4 @@ +export * from './super-admin-required' +export * from './tfa-required' +export * from './user-required' +export * from './verified-required' diff --git a/api/src/auth/super-admin-required.js b/api/src/auth/guards/super-admin-required.js similarity index 100% rename from api/src/auth/super-admin-required.js rename to api/src/auth/guards/super-admin-required.js diff --git a/api/src/auth/tfa-required.js b/api/src/auth/guards/tfa-required.js similarity index 100% rename from api/src/auth/tfa-required.js rename to api/src/auth/guards/tfa-required.js diff --git a/api/src/auth/user-required.js b/api/src/auth/guards/user-required.js similarity index 100% rename from api/src/auth/user-required.js rename to api/src/auth/guards/user-required.js diff --git a/api/src/auth/verified-required.js b/api/src/auth/guards/verified-required.js similarity index 100% rename from api/src/auth/verified-required.js rename to api/src/auth/guards/verified-required.js diff --git a/api/src/auth/index.js b/api/src/auth/index.js index beba36ce38..2f77a785a2 100644 --- a/api/src/auth/index.js +++ b/api/src/auth/index.js @@ -1,14 +1,4 @@ -export * from './check-domain-ownership' -export * from './check-domain-permission' -export * from './check-org-owner' -export * from './check-permission' -export * from './check-super-admin' -export * from './check-user-belongs-to-org' -export * from './check-user-is-admin-for-user' -export * from './generate-jwt' -export * from './salted-hash' -export * from './super-admin-required' -export * from './user-required' -export * from './verified-required' -export * from './verify-jwt' -export * from './tfa-required' +export * from './checks' +export * from './guards' +export * from './utils' +export * from './data-source' diff --git a/api/src/auth/loaders/__tests__/load-domain-permission-by-domain-id.test.js b/api/src/auth/loaders/__tests__/load-domain-permission-by-domain-id.test.js new file mode 100644 index 0000000000..60344802b4 --- /dev/null +++ b/api/src/auth/loaders/__tests__/load-domain-permission-by-domain-id.test.js @@ -0,0 +1,206 @@ +import { dbNameFromFile } from 'arango-tools' +import { ensureDatabase as ensure } from '../../../testUtilities' +import { setupI18n } from '@lingui/core' + +import { loadDomainPermissionByDomainId } from '../load-domain-permission-by-domain-id' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' + +const { DB_PASS: rootPass, DB_URL: url } = process.env + +describe('given the loadDomainPermissionByDomainId loader', () => { + let query, drop, truncate, collections, org, domain, i18n + + const consoleOutput = [] + const mockedError = (output) => consoleOutput.push(output) + + beforeAll(() => { + console.error = mockedError + }) + afterEach(() => { + consoleOutput.length = 0 + }) + + describe('given a successful domain permission load', () => { + let user + + beforeAll(async () => { + ;({ query, drop, truncate, collections } = await ensure({ + variables: { + dbname: dbNameFromFile(__filename), + username: 'root', + rootPassword: rootPass, + password: rootPass, + url, + }, + schema: dbschema, + })) + }) + + beforeEach(async () => { + user = await collections.users.save({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + tfaValidated: false, + emailValidated: false, + }) + org = await collections.organizations.save({ + verified: false, + orgDetails: { + en: { + slug: 'treasury-board-secretariat', + acronym: 'TBS', + name: 'Treasury Board of Canada Secretariat', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + fr: { + slug: 'secretariat-conseil-tresor', + acronym: 'SCT', + name: 'Secrétariat du Conseil Trésor du Canada', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + }, + }) + domain = await collections.domains.save({ + domain: 'test.gc.ca', + slug: 'test-gc-ca', + lastRan: null, + selectors: [], + }) + await collections.claims.save({ _from: org._id, _to: domain._id }) + }) + + afterEach(async () => { + await truncate() + }) + + afterAll(async () => { + await drop() + }) + + describe('when user is affiliated with an org that claims the domain', () => { + beforeEach(async () => { + await collections.affiliations.save({ + _from: org._id, + _to: user._id, + permission: 'user', + }) + }) + + it('returns true', async () => { + const loader = loadDomainPermissionByDomainId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(domain._id) + expect(result).toBe(true) + }) + }) + + describe('when user has no affiliation with any org claiming the domain', () => { + it('returns false', async () => { + const loader = loadDomainPermissionByDomainId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(domain._id) + expect(result).toBe(false) + }) + }) + + describe('when loading multiple domain IDs in one batch', () => { + let domain2 + + beforeEach(async () => { + domain2 = await collections.domains.save({ + domain: 'test2.gc.ca', + slug: 'test2-gc-ca', + lastRan: null, + selectors: [], + }) + await collections.affiliations.save({ _from: org._id, _to: user._id, permission: 'user' }) + }) + + it('returns correct permissions for each domain in a single batch', async () => { + const loader = loadDomainPermissionByDomainId({ query, userKey: user._key, i18n: {} }) + const [perm1, perm2] = await loader.loadMany([domain._id, domain2._id]) + expect(perm1).toBe(true) + expect(perm2).toBe(false) + }) + }) + }) + + describe('given an unsuccessful domain permission load', () => { + describe('language is set to english', () => { + beforeAll(() => { + i18n = setupI18n({ + locale: 'en', + localeData: { en: { plurals: {} }, fr: { plurals: {} } }, + locales: ['en', 'fr'], + messages: { en: englishMessages.messages, fr: frenchMessages.messages }, + }) + }) + + describe('database error on super admin check', () => { + it('throws an error', async () => { + const mockQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) + const loader = loadDomainPermissionByDomainId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('domains/1')).rejects.toThrow( + 'Permission check error. Unable to request domain information.', + ) + + expect(consoleOutput).toEqual([ + `Database error when checking super admin permission for user: users/1: Error: Database error occurred.`, + ]) + }) + }) + + describe('database error on batch domain permission check', () => { + it('throws an error', async () => { + const mockQuery = jest + .fn() + .mockResolvedValueOnce({ count: undefined }) + .mockRejectedValue(new Error('Database error occurred.')) + + const loader = loadDomainPermissionByDomainId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('domains/1')).rejects.toThrow( + 'Permission check error. Unable to request domain information.', + ) + + expect(consoleOutput).toEqual([ + `Database error when checking domain permissions for user: users/1: Error: Database error occurred.`, + ]) + }) + }) + + describe('cursor error on batch domain permission check', () => { + it('throws an error', async () => { + const errorCursor = { + forEach() { + throw new Error('Cursor error occurred.') + }, + } + const mockQuery = jest + .fn() + .mockResolvedValueOnce({ count: undefined }) + .mockResolvedValue(errorCursor) + + const loader = loadDomainPermissionByDomainId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('domains/1')).rejects.toThrow( + 'Permission check error. Unable to request domain information.', + ) + + expect(consoleOutput).toEqual([ + `Cursor error when checking domain permissions for user: users/1: Error: Cursor error occurred.`, + ]) + }) + }) + }) + }) +}) diff --git a/api/src/auth/loaders/__tests__/load-org-owner-by-org-id.test.js b/api/src/auth/loaders/__tests__/load-org-owner-by-org-id.test.js new file mode 100644 index 0000000000..1812c0c96a --- /dev/null +++ b/api/src/auth/loaders/__tests__/load-org-owner-by-org-id.test.js @@ -0,0 +1,200 @@ +import { dbNameFromFile } from 'arango-tools' +import { ensureDatabase as ensure } from '../../../testUtilities' +import { setupI18n } from '@lingui/core' + +import { loadOrgOwnerByOrgId } from '../load-org-owner-by-org-id' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' + +const { DB_PASS: rootPass, DB_URL: url } = process.env + +describe('given the loadOrgOwnerByOrgId loader', () => { + let query, drop, truncate, collections, user, org, i18n + + const consoleOutput = [] + const mockedError = (output) => consoleOutput.push(output) + + beforeAll(() => { + console.error = mockedError + }) + afterEach(() => { + consoleOutput.length = 0 + }) + + describe('given a successful org owner load', () => { + beforeAll(async () => { + ;({ query, drop, truncate, collections } = await ensure({ + variables: { + dbname: dbNameFromFile(__filename), + username: 'root', + rootPassword: rootPass, + password: rootPass, + url, + }, + schema: dbschema, + })) + }) + + beforeEach(async () => { + user = await collections.users.save({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + tfaValidated: false, + emailValidated: false, + }) + org = await collections.organizations.save({ + orgDetails: { + en: { + slug: 'treasury-board-secretariat', + acronym: 'TBS', + name: 'Treasury Board of Canada Secretariat', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + fr: { + slug: 'secretariat-conseil-tresor', + acronym: 'SCT', + name: 'Secrétariat du Conseil Trésor du Canada', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + }, + }) + }) + + afterEach(async () => { + await truncate() + }) + + afterAll(async () => { + await drop() + }) + + describe('when user is the owner', () => { + beforeEach(async () => { + await collections.affiliations.save({ _from: org._id, _to: user._id, permission: 'owner' }) + }) + + it('returns true', async () => { + const loader = loadOrgOwnerByOrgId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(org._id) + expect(result).toBe(true) + }) + }) + + describe('when user is not the owner', () => { + beforeEach(async () => { + await collections.affiliations.save({ _from: org._id, _to: user._id, permission: 'admin' }) + }) + + it('returns false', async () => { + const loader = loadOrgOwnerByOrgId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(org._id) + expect(result).toBe(false) + }) + }) + + describe('when user has no affiliation', () => { + it('returns false', async () => { + const loader = loadOrgOwnerByOrgId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(org._id) + expect(result).toBe(false) + }) + }) + + describe('when loading multiple org IDs in one batch', () => { + let org2 + + beforeEach(async () => { + org2 = await collections.organizations.save({ + orgDetails: { + en: { + slug: 'second-org', + acronym: 'SO', + name: 'Second Organization', + zone: 'FED', + sector: 'SO', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + fr: { + slug: 'deuxieme-org', + acronym: 'DO', + name: 'Deuxième Organisation', + zone: 'FED', + sector: 'DO', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + }, + }) + await collections.affiliations.save({ _from: org._id, _to: user._id, permission: 'owner' }) + await collections.affiliations.save({ _from: org2._id, _to: user._id, permission: 'admin' }) + }) + + it('returns correct ownership status for each org in a single batch', async () => { + const loader = loadOrgOwnerByOrgId({ query, userKey: user._key, i18n: {} }) + const [isOwner1, isOwner2] = await loader.loadMany([org._id, org2._id]) + expect(isOwner1).toBe(true) + expect(isOwner2).toBe(false) + }) + }) + }) + + describe('given an unsuccessful org owner load', () => { + describe('language is set to english', () => { + beforeAll(() => { + i18n = setupI18n({ + locale: 'en', + localeData: { en: { plurals: {} }, fr: { plurals: {} } }, + locales: ['en', 'fr'], + messages: { en: englishMessages.messages, fr: frenchMessages.messages }, + }) + }) + + describe('database error occurs', () => { + it('throws an error', async () => { + const mockQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) + const loader = loadOrgOwnerByOrgId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('organizations/1')).rejects.toThrow( + 'Unable to load owner information. Please try again.', + ) + + expect(consoleOutput).toEqual([ + `Database error when checking org ownership for user: 1: Error: Database error occurred.`, + ]) + }) + }) + + describe('cursor error occurs', () => { + it('throws an error', async () => { + const errorCursor = { + forEach() { + throw new Error('Cursor error occurred.') + }, + } + const mockQuery = jest.fn().mockResolvedValue(errorCursor) + const loader = loadOrgOwnerByOrgId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('organizations/1')).rejects.toThrow( + 'Unable to load owner information. Please try again.', + ) + + expect(consoleOutput).toEqual([ + `Cursor error when checking org ownership for user: 1: Error: Cursor error occurred.`, + ]) + }) + }) + }) + }) +}) diff --git a/api/src/auth/loaders/__tests__/load-permission-by-org-id.test.js b/api/src/auth/loaders/__tests__/load-permission-by-org-id.test.js new file mode 100644 index 0000000000..145bf1fa77 --- /dev/null +++ b/api/src/auth/loaders/__tests__/load-permission-by-org-id.test.js @@ -0,0 +1,263 @@ +import { dbNameFromFile } from 'arango-tools' +import { ensureDatabase as ensure } from '../../../testUtilities' +import { setupI18n } from '@lingui/core' + +import { loadPermissionByOrgId } from '../load-permission-by-org-id' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' +import dbschema from '../../../../database.json' + +const { DB_PASS: rootPass, DB_URL: url } = process.env + +describe('given the loadPermissionByOrgId loader', () => { + let query, drop, truncate, collections, i18n + + const consoleOutput = [] + const mockedError = (output) => consoleOutput.push(output) + + beforeAll(() => { + console.error = mockedError + }) + afterEach(() => { + consoleOutput.length = 0 + }) + + describe('given a successful permission load', () => { + let user, org + + beforeAll(async () => { + ;({ query, drop, truncate, collections } = await ensure({ + variables: { + dbname: dbNameFromFile(__filename), + username: 'root', + rootPassword: rootPass, + password: rootPass, + url, + }, + schema: dbschema, + })) + }) + + beforeEach(async () => { + user = await collections.users.save({ + userName: 'test.account@istio.actually.exists', + displayName: 'Test Account', + tfaValidated: false, + emailValidated: false, + }) + org = await collections.organizations.save({ + verified: false, + orgDetails: { + en: { + slug: 'treasury-board-secretariat', + acronym: 'TBS', + name: 'Treasury Board of Canada Secretariat', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + fr: { + slug: 'secretariat-conseil-tresor', + acronym: 'SCT', + name: 'Secrétariat du Conseil Trésor du Canada', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + }, + }) + }) + + afterEach(async () => { + await truncate() + }) + + afterAll(async () => { + await drop() + }) + + describe('when user is a super admin', () => { + beforeEach(async () => { + await collections.affiliations.save({ + _from: org._id, + _to: user._id, + permission: 'super_admin', + }) + }) + + it('returns super_admin for all requested org IDs', async () => { + const loader = loadPermissionByOrgId({ query, userKey: user._key, i18n: {} }) + const [result] = await loader.loadMany([org._id]) + expect(result).toEqual('super_admin') + }) + }) + + describe('when user is an admin', () => { + beforeEach(async () => { + await collections.affiliations.save({ + _from: org._id, + _to: user._id, + permission: 'admin', + }) + }) + + it('returns admin', async () => { + const loader = loadPermissionByOrgId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(org._id) + expect(result).toEqual('admin') + }) + }) + + describe('when user is a regular user', () => { + beforeEach(async () => { + await collections.affiliations.save({ + _from: org._id, + _to: user._id, + permission: 'user', + }) + }) + + it('returns user', async () => { + const loader = loadPermissionByOrgId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(org._id) + expect(result).toEqual('user') + }) + }) + + describe('when user has no affiliation with the org', () => { + it('returns null', async () => { + const loader = loadPermissionByOrgId({ query, userKey: user._key, i18n: {} }) + const result = await loader.load(org._id) + expect(result).toBeNull() + }) + }) + + describe('when loading multiple org IDs in one batch', () => { + let org2 + + beforeEach(async () => { + org2 = await collections.organizations.save({ + verified: false, + orgDetails: { + en: { + slug: 'second-org', + acronym: 'SO', + name: 'Second Organization', + zone: 'FED', + sector: 'SO', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + fr: { + slug: 'deuxieme-org', + acronym: 'DO', + name: 'Deuxième Organisation', + zone: 'FED', + sector: 'DO', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + }, + }) + await collections.affiliations.save({ _from: org._id, _to: user._id, permission: 'admin' }) + await collections.affiliations.save({ _from: org2._id, _to: user._id, permission: 'user' }) + }) + + it('returns correct permissions for each org in a single batch', async () => { + const loader = loadPermissionByOrgId({ query, userKey: user._key, i18n: {} }) + const [perm1, perm2] = await loader.loadMany([org._id, org2._id]) + expect(perm1).toEqual('admin') + expect(perm2).toEqual('user') + }) + }) + }) + + describe('given an unsuccessful permission load', () => { + describe('language is set to english', () => { + beforeAll(() => { + i18n = setupI18n({ + locale: 'en', + localeData: { en: { plurals: {} }, fr: { plurals: {} } }, + locales: ['en', 'fr'], + messages: { en: englishMessages.messages, fr: frenchMessages.messages }, + }) + }) + + describe('database error on super admin check', () => { + it('throws an error', async () => { + const mockQuery = jest.fn().mockRejectedValue(new Error('Database error occurred.')) + const loader = loadPermissionByOrgId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('organizations/1')).rejects.toThrow('Authentication error. Please sign in.') + + expect(consoleOutput).toEqual([ + `Database error when checking super admin permission for user: users/1: Error: Database error occurred.`, + ]) + }) + }) + + describe('cursor error on super admin check', () => { + it('throws an error', async () => { + const cursor = { + next() { + throw new Error('Cursor error occurred.') + }, + } + const mockQuery = jest.fn().mockResolvedValue(cursor) + const loader = loadPermissionByOrgId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('organizations/1')).rejects.toThrow('Unable to check permission. Please try again.') + + expect(consoleOutput).toEqual([ + `Cursor error when checking super admin permission for user: users/1: Error: Cursor error occurred.`, + ]) + }) + }) + + describe('database error on batch permission check', () => { + it('throws an error', async () => { + const mockQuery = jest + .fn() + .mockResolvedValueOnce({ next: () => undefined }) + .mockRejectedValue(new Error('Database error occurred.')) + + const loader = loadPermissionByOrgId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('organizations/1')).rejects.toThrow('Authentication error. Please sign in.') + + expect(consoleOutput).toEqual([ + `Database error when checking permissions for user: users/1: Error: Database error occurred.`, + ]) + }) + }) + + describe('cursor error on batch permission check', () => { + it('throws an error', async () => { + const errorCursor = { + forEach() { + throw new Error('Cursor error occurred.') + }, + } + const mockQuery = jest + .fn() + .mockResolvedValueOnce({ next: () => undefined }) + .mockResolvedValue(errorCursor) + + const loader = loadPermissionByOrgId({ query: mockQuery, userKey: '1', i18n }) + + await expect(loader.load('organizations/1')).rejects.toThrow('Unable to check permission. Please try again.') + + expect(consoleOutput).toEqual([ + `Cursor error when checking permissions for user: users/1: Error: Cursor error occurred.`, + ]) + }) + }) + }) + }) +}) diff --git a/api/src/auth/loaders/index.js b/api/src/auth/loaders/index.js new file mode 100644 index 0000000000..ed64fc5701 --- /dev/null +++ b/api/src/auth/loaders/index.js @@ -0,0 +1,3 @@ +export * from './load-permission-by-org-id' +export * from './load-domain-permission-by-domain-id' +export * from './load-org-owner-by-org-id' diff --git a/api/src/auth/loaders/load-domain-permission-by-domain-id.js b/api/src/auth/loaders/load-domain-permission-by-domain-id.js new file mode 100644 index 0000000000..ce2f8b3cef --- /dev/null +++ b/api/src/auth/loaders/load-domain-permission-by-domain-id.js @@ -0,0 +1,65 @@ +import DataLoader from 'dataloader' +import { t } from '@lingui/macro' + +export const loadDomainPermissionByDomainId = ({ query, userKey, i18n }) => + new DataLoader(async (domainIds) => { + const userKeyString = `users/${userKey}` + + // Check super admin once for the whole batch (mirrors existing checkDomainPermission logic) + let superAdminCursor + try { + superAdminCursor = await query` + WITH affiliations, organizations, users + FOR v, e IN 1..1 ANY ${userKeyString} affiliations + FILTER e.permission == 'super_admin' + RETURN e._from + ` + } catch (err) { + console.error(`Database error when checking super admin permission for user: ${userKeyString}: ${err}`) + throw new Error(i18n._(t`Permission check error. Unable to request domain information.`)) + } + + if (superAdminCursor.count > 0) { + return domainIds.map(() => true) + } + + // Batch domain permission check across all domain IDs in one query + let cursor + try { + cursor = await query` + WITH affiliations, claims, domains, organizations, users + LET userAffiliations = ( + FOR v, e IN 1..1 ANY ${userKeyString} affiliations + FILTER e.permission != "pending" + RETURN v + ) + LET hasVerifiedOrgAffiliation = POSITION(userAffiliations[*].verified, true) + FOR domainId IN ${domainIds} + LET domainOrgClaims = ( + FOR v, e IN 1..1 ANY domainId claims + RETURN v + ) + LET domainBelongsToVerifiedOrg = POSITION(domainOrgClaims[*].verified, true) + LET affiliatedClaims = INTERSECTION(userAffiliations, domainOrgClaims) + RETURN { + domainId: domainId, + permitted: (domainBelongsToVerifiedOrg && hasVerifiedOrgAffiliation) || LENGTH(affiliatedClaims) > 0 + } + ` + } catch (err) { + console.error(`Database error when checking domain permissions for user: ${userKeyString}: ${err}`) + throw new Error(i18n._(t`Permission check error. Unable to request domain information.`)) + } + + const permMap = {} + try { + await cursor.forEach(({ domainId, permitted }) => { + permMap[domainId] = permitted + }) + } catch (err) { + console.error(`Cursor error when checking domain permissions for user: ${userKeyString}: ${err}`) + throw new Error(i18n._(t`Permission check error. Unable to request domain information.`)) + } + + return domainIds.map((id) => permMap[id] ?? false) + }) diff --git a/api/src/auth/loaders/load-org-owner-by-org-id.js b/api/src/auth/loaders/load-org-owner-by-org-id.js new file mode 100644 index 0000000000..88232815d6 --- /dev/null +++ b/api/src/auth/loaders/load-org-owner-by-org-id.js @@ -0,0 +1,37 @@ +import DataLoader from 'dataloader' +import { t } from '@lingui/macro' + +export const loadOrgOwnerByOrgId = ({ query, userKey, i18n }) => + new DataLoader(async (orgIds) => { + const userIdString = `users/${userKey}` + + let cursor + try { + cursor = await query` + WITH affiliations, organizations, users + LET userId = ${userIdString} + FOR orgId IN ${orgIds} + LET isOwner = FIRST( + FOR v, e IN 1..1 OUTBOUND orgId affiliations + FILTER e._to == userId + RETURN e.permission == "owner" + ) + RETURN { orgId: orgId, isOwner: isOwner == true } + ` + } catch (err) { + console.error(`Database error when checking org ownership for user: ${userKey}: ${err}`) + throw new Error(i18n._(t`Unable to load owner information. Please try again.`)) + } + + const ownerMap = {} + try { + await cursor.forEach(({ orgId, isOwner }) => { + ownerMap[orgId] = isOwner + }) + } catch (err) { + console.error(`Cursor error when checking org ownership for user: ${userKey}: ${err}`) + throw new Error(i18n._(t`Unable to load owner information. Please try again.`)) + } + + return orgIds.map((id) => ownerMap[id] ?? false) + }) diff --git a/api/src/auth/loaders/load-permission-by-org-id.js b/api/src/auth/loaders/load-permission-by-org-id.js new file mode 100644 index 0000000000..cccc12aac5 --- /dev/null +++ b/api/src/auth/loaders/load-permission-by-org-id.js @@ -0,0 +1,77 @@ +import DataLoader from 'dataloader' +import { t } from '@lingui/macro' + +export const loadPermissionByOrgId = ({ query, userKey, i18n }) => + new DataLoader(async (orgIds) => { + const userKeyString = `users/${userKey}` + + // Check for super admin once for the whole batch + let superAdminCursor + try { + superAdminCursor = await query` + WITH affiliations, organizations, users + FOR v, e IN 1..1 INBOUND ${userKeyString} affiliations + FILTER e.permission == "super_admin" + RETURN e.permission + ` + } catch (err) { + console.error(`Database error when checking super admin permission for user: ${userKeyString}: ${err}`) + throw new Error(i18n._(t`Authentication error. Please sign in.`)) + } + + let superAdminPermission + try { + superAdminPermission = await superAdminCursor.next() + } catch (err) { + console.error(`Cursor error when checking super admin permission for user: ${userKeyString}: ${err}`) + throw new Error(i18n._(t`Unable to check permission. Please try again.`)) + } + + if (superAdminPermission === 'super_admin') { + return orgIds.map(() => 'super_admin') + } + + // Batch permission check across all org IDs in one query + let cursor + try { + cursor = await query` + WITH affiliations, organizations, users + LET userAffiliations = ( + FOR v, e IN 1..1 ANY ${userKeyString} affiliations + FILTER e.permission != "pending" + RETURN v + ) + LET hasVerifiedOrgAffiliation = POSITION(userAffiliations[*].verified, true) + FOR orgId IN ${orgIds} + LET org = DOCUMENT(orgId) + LET orgIsVerified = org.verified + LET userOrgAffiliation = FIRST( + FOR v, e IN 1..1 ANY ${userKeyString} affiliations + FILTER e._from == orgId + RETURN e + ) + RETURN { + orgId: orgId, + permission: userOrgAffiliation.permission IN ["user", "admin", "owner", "super_admin"] ? userOrgAffiliation.permission + : (orgIsVerified && hasVerifiedOrgAffiliation) ? "user" + : userOrgAffiliation.permission == "pending" ? userOrgAffiliation + : null + } + ` + } catch (err) { + console.error(`Database error when checking permissions for user: ${userKeyString}: ${err}`) + throw new Error(i18n._(t`Authentication error. Please sign in.`)) + } + + const permMap = {} + try { + await cursor.forEach(({ orgId, permission }) => { + permMap[orgId] = permission + }) + } catch (err) { + console.error(`Cursor error when checking permissions for user: ${userKeyString}: ${err}`) + throw new Error(i18n._(t`Unable to check permission. Please try again.`)) + } + + return orgIds.map((id) => permMap[id] ?? null) + }) diff --git a/api/src/auth/__tests__/generate-jwt.test.js b/api/src/auth/utils/__tests__/generate-jwt.test.js similarity index 100% rename from api/src/auth/__tests__/generate-jwt.test.js rename to api/src/auth/utils/__tests__/generate-jwt.test.js diff --git a/api/src/auth/__tests__/salted-hash.test.js b/api/src/auth/utils/__tests__/salted-hash.test.js similarity index 100% rename from api/src/auth/__tests__/salted-hash.test.js rename to api/src/auth/utils/__tests__/salted-hash.test.js diff --git a/api/src/auth/__tests__/verify-jwt.test.js b/api/src/auth/utils/__tests__/verify-jwt.test.js similarity index 95% rename from api/src/auth/__tests__/verify-jwt.test.js rename to api/src/auth/utils/__tests__/verify-jwt.test.js index a24e851c48..f53cf66a7f 100644 --- a/api/src/auth/__tests__/verify-jwt.test.js +++ b/api/src/auth/utils/__tests__/verify-jwt.test.js @@ -2,8 +2,8 @@ import jwt from 'jsonwebtoken' import {setupI18n} from '@lingui/core' import {verifyToken} from '../index' -import englishMessages from '../../locale/en/messages' -import frenchMessages from '../../locale/fr/messages' +import englishMessages from '../../../locale/en/messages' +import frenchMessages from '../../../locale/fr/messages' const {AUTHENTICATED_KEY} = process.env diff --git a/api/src/auth/generate-jwt.js b/api/src/auth/utils/generate-jwt.js similarity index 100% rename from api/src/auth/generate-jwt.js rename to api/src/auth/utils/generate-jwt.js diff --git a/api/src/auth/utils/index.js b/api/src/auth/utils/index.js new file mode 100644 index 0000000000..d6160f558e --- /dev/null +++ b/api/src/auth/utils/index.js @@ -0,0 +1,3 @@ +export * from './generate-jwt' +export * from './salted-hash' +export * from './verify-jwt' diff --git a/api/src/auth/salted-hash.js b/api/src/auth/utils/salted-hash.js similarity index 100% rename from api/src/auth/salted-hash.js rename to api/src/auth/utils/salted-hash.js diff --git a/api/src/auth/verify-jwt.js b/api/src/auth/utils/verify-jwt.js similarity index 100% rename from api/src/auth/verify-jwt.js rename to api/src/auth/utils/verify-jwt.js diff --git a/api/src/create-context.js b/api/src/create-context.js index 84d1a7e963..ee4bcc9f05 100644 --- a/api/src/create-context.js +++ b/api/src/create-context.js @@ -7,7 +7,16 @@ import jwt from 'jsonwebtoken' import { loadUserByKey } from './user/loaders' import { cleanseInput, decryptPhoneNumber, slugify } from './validators' import { initializeLoaders } from './initialize-loaders' +import { SummariesDataSource } from './summaries' +import { DnsScanDataSource } from './dns-scan' +import { WebScanDataSource } from './web-scan' +import { AuditLogsDataSource } from './audit-logs' +import { AdditionalFindingsDataSource } from './additional-findings' +import { GuidanceTagDataSource } from './guidance-tag' +import { OrganizationDataSource } from './organization' +import { TagsDataSource } from './tags' import { + AuthDataSource, checkDomainOwnership, checkDomainPermission, checkOrgOwner, @@ -33,6 +42,7 @@ import { sendPasswordResetEmail, sendUpdatedUserNameEmail, sendVerificationEmail, + sendRoleChangeEmail, } from './notify' export async function createContext({ @@ -130,10 +140,21 @@ export async function createContext({ i18n, }), sendVerificationEmail: sendVerificationEmail({ notifyClient, i18n }), + sendRoleChangeEmail: sendRoleChangeEmail({ notifyClient, i18n }), + }, + dataSources: { + auth: new AuthDataSource({ query, userKey, i18n }), + summaries: new SummariesDataSource({ query, userKey, cleanseInput, i18n }), + additionalFindings: new AdditionalFindingsDataSource({ query, userKey, i18n, language: request.language }), + auditLogs: new AuditLogsDataSource({ query, userKey, cleanseInput, i18n, transaction, collections }), + dnsScan: new DnsScanDataSource({ query, userKey, cleanseInput, i18n }), + guidanceTag: new GuidanceTagDataSource({ query, userKey, i18n, language: request.language, cleanseInput }), + organization: new OrganizationDataSource({ query, userKey, i18n, language: request.language, cleanseInput, loginRequiredBool, transaction, collections }), + tags: new TagsDataSource({ query, userKey, i18n, language: request.language, transaction, collections }), + webScan: new WebScanDataSource({ query, userKey, cleanseInput, i18n }), }, loaders: initializeLoaders({ query, - db, userKey, i18n, language: request.language, diff --git a/api/src/dmarc-summaries/objects/__tests__/dkim-failure-table.test.js b/api/src/dmarc-summaries/objects/__tests__/dkim-failure-table.test.js index e69d17b6d7..133de70e0f 100644 --- a/api/src/dmarc-summaries/objects/__tests__/dkim-failure-table.test.js +++ b/api/src/dmarc-summaries/objects/__tests__/dkim-failure-table.test.js @@ -164,8 +164,8 @@ describe('given the dkimFailureTable gql object', () => { { guidance: 'agg1' }, {}, { - loaders: { - loadGuidanceTagByTagId: jest.fn().mockReturnValue([expectedResults]), + dataSources: { + guidanceTag: { byTagId: jest.fn().mockReturnValue([expectedResults]) }, }, }, ), @@ -183,8 +183,8 @@ describe('given the dkimFailureTable gql object', () => { { guidance: null }, {}, { - loaders: { - loadGuidanceTagByTagId: jest.fn().mockReturnValue(expectedResults), + dataSources: { + guidanceTag: { byTagId: jest.fn().mockReturnValue(expectedResults) }, }, }, ), diff --git a/api/src/dmarc-summaries/objects/__tests__/spf-failure-table.test.js b/api/src/dmarc-summaries/objects/__tests__/spf-failure-table.test.js index 51f78bccce..c35d341b5b 100644 --- a/api/src/dmarc-summaries/objects/__tests__/spf-failure-table.test.js +++ b/api/src/dmarc-summaries/objects/__tests__/spf-failure-table.test.js @@ -130,8 +130,8 @@ describe('given spfFailureTable gql object', () => { { guidance: 'agg1' }, {}, { - loaders: { - loadGuidanceTagByTagId: jest.fn().mockReturnValue([expectedResult]), + dataSources: { + guidanceTag: { byTagId: jest.fn().mockReturnValue([expectedResult]) }, }, }, ), @@ -149,8 +149,8 @@ describe('given spfFailureTable gql object', () => { { guidance: null }, {}, { - loaders: { - loadGuidanceTagByTagId: jest.fn().mockReturnValue(expectedResult), + dataSources: { + guidanceTag: { byTagId: jest.fn().mockReturnValue(expectedResult) }, }, }, ), diff --git a/api/src/dmarc-summaries/objects/dkim-failure-table.js b/api/src/dmarc-summaries/objects/dkim-failure-table.js index 0cf8c738a1..140022b472 100644 --- a/api/src/dmarc-summaries/objects/dkim-failure-table.js +++ b/api/src/dmarc-summaries/objects/dkim-failure-table.js @@ -49,9 +49,9 @@ export const dkimFailureTableType = new GraphQLObjectType({ guidanceTag: { type: guidanceTagType, description: 'Guidance for any issues that were found from the report.', - resolve: async ({ guidance }, _args, { loaders: { loadGuidanceTagByTagId } }) => { + resolve: async ({ guidance }, _args, { dataSources: { guidanceTag } }) => { if (guidance) { - const guidanceTags = await loadGuidanceTagByTagId({ tags: [guidance] }) + const guidanceTags = await guidanceTag.byTagId({ tags: [guidance] }) return guidanceTags[0] } return {} diff --git a/api/src/dmarc-summaries/objects/spf-failure-table.js b/api/src/dmarc-summaries/objects/spf-failure-table.js index bb5695fdb4..f15cddf528 100644 --- a/api/src/dmarc-summaries/objects/spf-failure-table.js +++ b/api/src/dmarc-summaries/objects/spf-failure-table.js @@ -28,9 +28,9 @@ export const spfFailureTableType = new GraphQLObjectType({ guidanceTag: { type: guidanceTagType, description: 'Guidance for any issues that were found from the report.', - resolve: async ({ guidance }, _args, { loaders: { loadGuidanceTagByTagId } }) => { + resolve: async ({ guidance }, _args, { dataSources: { guidanceTag } }) => { if (guidance) { - const guidanceTags = await loadGuidanceTagByTagId({ tags: [guidance] }) + const guidanceTags = await guidanceTag.byTagId({ tags: [guidance] }) return guidanceTags[0] } return {} diff --git a/api/src/dns-scan/data-source.js b/api/src/dns-scan/data-source.js new file mode 100644 index 0000000000..b7d2321215 --- /dev/null +++ b/api/src/dns-scan/data-source.js @@ -0,0 +1,8 @@ +import { loadDnsByKey, loadDnsConnectionsByDomainId } from './loaders' + +export class DnsScanDataSource { + constructor({ query, userKey, cleanseInput, i18n }) { + this.byKey = loadDnsByKey({ query, userKey, i18n }) + this.getConnectionsByDomainId = loadDnsConnectionsByDomainId({ query, userKey, cleanseInput, i18n }) + } +} diff --git a/api/src/dns-scan/index.js b/api/src/dns-scan/index.js index 6d2a5b5879..52de3be3af 100644 --- a/api/src/dns-scan/index.js +++ b/api/src/dns-scan/index.js @@ -1,3 +1,4 @@ +export * from './data-source' export * from './inputs' export * from './loaders' export * from './objects' diff --git a/api/src/dns-scan/loaders/index.js b/api/src/dns-scan/loaders/index.js index 6d093db6d4..9b63653ab8 100644 --- a/api/src/dns-scan/loaders/index.js +++ b/api/src/dns-scan/loaders/index.js @@ -1,3 +1,2 @@ export * from './load-dns-by-key' export * from './load-dns-connections-by-domain-id' -export * from './load-mx-record-diff-by-domain-id' diff --git a/api/src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js b/api/src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js deleted file mode 100644 index a84eeb956d..0000000000 --- a/api/src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js +++ /dev/null @@ -1,241 +0,0 @@ -import { aql } from 'arangojs' -import { t } from '@lingui/macro' - -export const loadMxRecordDiffByDomainId = - ({ query, userKey, cleanseInput, i18n }) => - async ({ limit, domainId, startDate, endDate, after, before, offset, orderBy }) => { - if (limit === undefined) { - console.warn(`User: ${userKey} did not set \`limit\` argument for: loadMxRecordDiffByDomainId.`) - throw new Error(i18n._(t`You must provide a \`limit\` value to properly paginate the \`MXRecord\` connection.`)) - } - - if (limit <= 0 || limit > 100) { - console.warn(`User: ${userKey} set \`limit\` argument outside accepted range: loadMxRecordDiffByDomainId.`) - throw new Error( - i18n._( - t`You must provide a \`limit\` value in the range of 1-100 to properly paginate the \`MXRecord\` connection.`, - ), - ) - } - - const paginationMethodCount = [before, after, offset].reduce( - (paginationMethod, currentValue) => currentValue + (paginationMethod === undefined), - 0, - ) - - if (paginationMethodCount > 1) { - console.warn(`User: ${userKey} set multiple pagination methods for: loadMxRecordDiffByDomainId.`) - throw new Error( - i18n._( - t`You must provide at most one pagination method (\`before\`, \`after\`, \`offset\`) value to properly paginate the \`MXRecord\` connection.`, - ), - ) - } - - before = cleanseInput(before) - after = cleanseInput(after) - - const usingRelayExplicitly = !!(before || after) - - const resolveCursor = (cursor) => { - const cursorString = Buffer.from(cursor, 'base64').toString('utf8').split('|') - - return cursorString.reduce((acc, currentValue) => { - const [type, id] = currentValue.split('::') - acc.push({ type, id }) - return acc - }, []) - } - let relayBeforeTemplate = aql`` - let relayAfterTemplate = aql`` - if (usingRelayExplicitly) { - const cursorList = resolveCursor(after || before) - - if (cursorList.length === 0 || cursorList > 2) { - // TODO: throw error - } - - if (cursorList.at(-1).type !== 'id') { - // id field should always be last property - // TODO: throw error - } - - const orderByDirectionArrow = - orderBy?.direction === 'DESC' ? aql`<` : orderBy?.direction === 'ASC' ? aql`>` : null - const reverseOrderByDirectionArrow = - orderBy?.direction === 'DESC' ? aql`>` : orderBy?.direction === 'ASC' ? aql`<` : null - - relayBeforeTemplate = aql`FILTER TO_NUMBER(dnsScan._key) < TO_NUMBER(${cursorList[0].id})` - relayAfterTemplate = aql`FILTER TO_NUMBER(dnsScan._key) > TO_NUMBER(${cursorList[0].id})` - - if (cursorList.length === 2) { - relayAfterTemplate = aql` - FILTER dnsScan.${cursorList[0].type} ${orderByDirectionArrow || aql`>`} ${cursorList[0].id} - OR (dnsScan.${cursorList[0].type} == ${cursorList[0].id} - AND TO_NUMBER(dnsScan._key) > TO_NUMBER(${cursorList[1].id})) - ` - - relayBeforeTemplate = aql` - FILTER dnsScan.${cursorList[0].type} ${reverseOrderByDirectionArrow || aql`<`} ${cursorList[0].id} - OR (dnsScan.${cursorList[0].type} == ${cursorList[0].id} - AND TO_NUMBER(dnsScan._key) < TO_NUMBER(${cursorList[1].id})) - ` - } - } - - const relayDirectionString = before ? aql`DESC` : aql`ASC` - - let sortTemplate - if (!orderBy) { - sortTemplate = aql`SORT TO_NUMBER(dnsScan._key) ${relayDirectionString}` - } else { - sortTemplate = aql`SORT dnsScan.${orderBy.field} ${orderBy.direction}, TO_NUMBER(dnsScan._key) ${relayDirectionString}` - } - - let startDateFilter = aql`` - if (typeof startDate !== 'undefined') { - startDateFilter = aql` - FILTER DATE_FORMAT(dnsScan.timestamp, '%yyyy-%mm-%dd') >= DATE_FORMAT(${startDate}, '%yyyy-%mm-%dd')` - } - - let endDateFilter = aql`` - if (typeof endDate !== 'undefined') { - endDateFilter = aql` - FILTER DATE_FORMAT(dnsScan.timestamp, '%yyyy-%mm-%dd') <= DATE_FORMAT(${endDate}, '%yyyy-%mm-%dd')` - } - - const removeExtraSliceTemplate = aql`SLICE(dnsScansPlusOne, 0, ${limit})` - const dnsScanQuery = aql` - WITH dns, domains - LET dnsScansPlusOne = ( - FOR dnsScan, e IN 1 OUTBOUND ${domainId} domainsDNS - FILTER dnsScan.mxRecords.diff == true - ${startDateFilter} - ${endDateFilter} - ${before ? relayBeforeTemplate : relayAfterTemplate} - ${sortTemplate} - LIMIT ${limit + 1} - RETURN { id: dnsScan._key, _type: "dnsScan", timestamp: dnsScan.timestamp, mxRecords: dnsScan.mxRecords } - ) - LET hasMoreRelayPage = LENGTH(dnsScansPlusOne) == ${limit} + 1 - LET hasReversePage = ${!usingRelayExplicitly} ? false : (LENGTH( - FOR dnsScan, e IN 1 OUTBOUND ${domainId} domainsDNS - FILTER dnsScan.mxRecords.diff == true - ${startDateFilter} - ${endDateFilter} - ${before ? relayAfterTemplate : relayBeforeTemplate} - LIMIT 1 - RETURN true - ) > 0) ? true : false - LET totalCount = COUNT( - FOR dnsScan, e IN 1 OUTBOUND ${domainId} domainsDNS - FILTER dnsScan.mxRecords.diff == true - ${startDateFilter} - ${endDateFilter} - RETURN true - ) - LET mxRecords = ${removeExtraSliceTemplate} - - RETURN { - "mxRecords": mxRecords, - "hasMoreRelayPage": hasMoreRelayPage, - "hasReversePage": hasReversePage, - "totalCount": totalCount - } - ` - - let mxRecordCursor - try { - mxRecordCursor = await query`${dnsScanQuery}` - } catch (err) { - console.error( - `Database error occurred while user: ${userKey} was trying to get cursor for DNS document with cursor '${ - after || before - }' for domain '${domainId}', error: ${err}`, - ) - throw new Error(i18n._(t`Unable to load DNS scan(s). Please try again.`)) - } - - let mxRecordInfo - try { - mxRecordInfo = await mxRecordCursor.next() - } catch (err) { - console.error( - `Cursor error occurred while user: ${userKey} was trying to get DNS information for ${domainId}, error: ${err}`, - ) - throw new Error(i18n._(t`Unable to load DNS scan(s). Please try again.`)) - } - - const mxRecords = mxRecordInfo.mxRecords - - if (mxRecords.length === 0) { - return { - edges: [], - totalCount: mxRecordInfo.totalCount, - pageInfo: { - hasPreviousPage: !usingRelayExplicitly - ? false - : after - ? mxRecordInfo.hasReversePage - : mxRecordInfo.hasMoreRelayPage, - hasNextPage: after || !usingRelayExplicitly ? mxRecordInfo.hasMoreRelayPage : mxRecordInfo.hasReversePage, - startCursor: null, - endCursor: null, - }, - } - } - - const toCursorString = (cursorObjects) => { - const cursorStringArray = cursorObjects.reduce((acc, cursorObject) => { - if (cursorObject.type === undefined || cursorObject.id === undefined) { - // TODO: throw error - } - acc.push(`${cursorObject.type}::${cursorObject.id}`) - return acc - }, []) - const cursorString = cursorStringArray.join('|') - return Buffer.from(cursorString, 'utf8').toString('base64') - } - - const edges = mxRecords.map((mxRecord) => { - let cursor - if (orderBy) { - cursor = toCursorString([ - { - type: orderBy.field, - id: mxRecord[orderBy.field], - }, - { - type: 'id', - id: mxRecord._key, - }, - ]) - } else { - cursor = toCursorString([ - { - type: 'id', - id: mxRecord._key, - }, - ]) - } - return { - cursor: cursor, - node: mxRecord, - } - }) - - return { - edges: edges, - totalCount: mxRecordInfo.totalCount, - pageInfo: { - hasPreviousPage: !usingRelayExplicitly - ? false - : after - ? mxRecordInfo.hasReversePage - : mxRecordInfo.hasMoreRelayPage, - hasNextPage: after || !usingRelayExplicitly ? mxRecordInfo.hasMoreRelayPage : mxRecordInfo.hasReversePage, - endCursor: edges.length > 0 ? edges.at(-1).cursor : null, - startCursor: edges.length > 0 ? edges[0].cursor : null, - }, - } - } diff --git a/api/src/dns-scan/objects/dkim-selector-result.js b/api/src/dns-scan/objects/dkim-selector-result.js index 48ca2cd31c..0a51b0a474 100644 --- a/api/src/dns-scan/objects/dkim-selector-result.js +++ b/api/src/dns-scan/objects/dkim-selector-result.js @@ -42,22 +42,22 @@ export const dkimSelectorResultType = new GraphQLObjectType({ positiveTags: { type: new GraphQLList(guidanceTagType), description: `List of positive tags for the scanned domain from this scan.`, - resolve: async ({ positiveTags }, _, { loaders: { loadDkimGuidanceTagByTagId } }) => { - return await loadDkimGuidanceTagByTagId({ tags: positiveTags }) + resolve: async ({ positiveTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.dkimByTagId({ tags: positiveTags }) }, }, neutralTags: { type: new GraphQLList(guidanceTagType), description: `List of neutral tags for the scanned domain from this scan.`, - resolve: async ({ neutralTags }, _, { loaders: { loadDkimGuidanceTagByTagId } }) => { - return await loadDkimGuidanceTagByTagId({ tags: neutralTags }) + resolve: async ({ neutralTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.dkimByTagId({ tags: neutralTags }) }, }, negativeTags: { type: new GraphQLList(guidanceTagType), description: `List of negative tags for the scanned domain from this scan.`, - resolve: async ({ negativeTags }, _, { loaders: { loadDkimGuidanceTagByTagId } }) => { - return await loadDkimGuidanceTagByTagId({ tags: negativeTags }) + resolve: async ({ negativeTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.dkimByTagId({ tags: negativeTags }) }, }, }), diff --git a/api/src/dns-scan/objects/dkim.js b/api/src/dns-scan/objects/dkim.js index 6eae47c02b..ed5ab22d16 100644 --- a/api/src/dns-scan/objects/dkim.js +++ b/api/src/dns-scan/objects/dkim.js @@ -13,22 +13,22 @@ export const dkimType = new GraphQLObjectType({ positiveTags: { type: new GraphQLList(guidanceTagType), description: `List of positive tags for the scanned domain from this scan.`, - resolve: async ({ positiveTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: positiveTags }) + resolve: async ({ positiveTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: positiveTags }) }, }, neutralTags: { type: new GraphQLList(guidanceTagType), description: `List of neutral tags for the scanned domain from this scan.`, - resolve: async ({ neutralTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: neutralTags }) + resolve: async ({ neutralTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: neutralTags }) }, }, negativeTags: { type: new GraphQLList(guidanceTagType), description: `List of negative tags for the scanned domain from this scan.`, - resolve: async ({ negativeTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: negativeTags }) + resolve: async ({ negativeTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: negativeTags }) }, }, selectors: { diff --git a/api/src/dns-scan/objects/dmarc.js b/api/src/dns-scan/objects/dmarc.js index 323de4ef31..dcaf40eb53 100644 --- a/api/src/dns-scan/objects/dmarc.js +++ b/api/src/dns-scan/objects/dmarc.js @@ -39,22 +39,22 @@ subdomains where mail is failing the DMARC authentication and alignment checks.` positiveTags: { type: new GraphQLList(guidanceTagType), description: `List of positive tags for the scanned domain from this scan.`, - resolve: async ({ positiveTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: positiveTags }) + resolve: async ({ positiveTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: positiveTags }) }, }, neutralTags: { type: new GraphQLList(guidanceTagType), description: `List of neutral tags for the scanned domain from this scan.`, - resolve: async ({ neutralTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: neutralTags }) + resolve: async ({ neutralTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: neutralTags }) }, }, negativeTags: { type: new GraphQLList(guidanceTagType), description: `List of negative tags for the scanned domain from this scan.`, - resolve: async ({ negativeTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: negativeTags }) + resolve: async ({ negativeTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: negativeTags }) }, }, }), diff --git a/api/src/dns-scan/objects/index.js b/api/src/dns-scan/objects/index.js index 1308111823..3ff3084458 100644 --- a/api/src/dns-scan/objects/index.js +++ b/api/src/dns-scan/objects/index.js @@ -3,6 +3,5 @@ export * from './dkim-selector-result' export * from './dmarc' export * from './dns-scan' export * from './dns-scan-connection' -export * from './mx-record-connection' export * from './mx-record' export * from './spf' diff --git a/api/src/dns-scan/objects/mx-record-connection.js b/api/src/dns-scan/objects/mx-record-connection.js deleted file mode 100644 index f33a7e3143..0000000000 --- a/api/src/dns-scan/objects/mx-record-connection.js +++ /dev/null @@ -1,16 +0,0 @@ -import { GraphQLInt } from 'graphql' -import { connectionDefinitions } from 'graphql-relay' - -import { mxRecordDiffType } from './mx-record' - -export const mxRecordConnection = connectionDefinitions({ - name: 'MXRecordDiff', - nodeType: mxRecordDiffType, - connectionFields: () => ({ - totalCount: { - type: GraphQLInt, - description: 'The total amount of DNS scans related to a given domain.', - resolve: ({ totalCount }) => totalCount, - }, - }), -}) diff --git a/api/src/dns-scan/objects/mx-record.js b/api/src/dns-scan/objects/mx-record.js index d6ed6341ac..f4a339f4f0 100644 --- a/api/src/dns-scan/objects/mx-record.js +++ b/api/src/dns-scan/objects/mx-record.js @@ -1,6 +1,4 @@ import { GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLString } from 'graphql' -import { GraphQLDateTime } from 'graphql-scalars' -import { globalIdField } from 'graphql-relay' export const mxHostType = new GraphQLObjectType({ name: 'MXHost', @@ -38,20 +36,3 @@ export const mxRecordType = new GraphQLObjectType({ }, }), }) - -export const mxRecordDiffType = new GraphQLObjectType({ - name: 'MXRecordDiff', - fields: () => ({ - id: globalIdField('dns'), - timestamp: { - type: GraphQLDateTime, - description: `The time when the scan was initiated.`, - resolve: ({ timestamp }) => new Date(timestamp), - }, - mxRecords: { - type: mxRecordType, - description: `The MX records for the domain (if they exist).`, - resolve: ({ mxRecords }) => mxRecords, - }, - }), -}) diff --git a/api/src/dns-scan/objects/spf.js b/api/src/dns-scan/objects/spf.js index 5e2fdd791e..9104d7aa14 100644 --- a/api/src/dns-scan/objects/spf.js +++ b/api/src/dns-scan/objects/spf.js @@ -27,22 +27,22 @@ export const spfType = new GraphQLObjectType({ positiveTags: { type: new GraphQLList(guidanceTagType), description: `List of positive tags for the scanned domain from this scan.`, - resolve: async ({ positiveTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: positiveTags }) + resolve: async ({ positiveTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: positiveTags }) }, }, neutralTags: { type: new GraphQLList(guidanceTagType), description: `List of neutral tags for the scanned domain from this scan.`, - resolve: async ({ neutralTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: neutralTags }) + resolve: async ({ neutralTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: neutralTags }) }, }, negativeTags: { type: new GraphQLList(guidanceTagType), description: `List of negative tags for the scanned domain from this scan.`, - resolve: async ({ negativeTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: negativeTags }) + resolve: async ({ negativeTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: negativeTags }) }, }, }), diff --git a/api/src/domain/helpers/__tests__/build-domain-filters.test.js b/api/src/domain/helpers/__tests__/build-domain-filters.test.js new file mode 100644 index 0000000000..6bc33450a2 --- /dev/null +++ b/api/src/domain/helpers/__tests__/build-domain-filters.test.js @@ -0,0 +1,267 @@ +import { buildDomainFilters } from '../build-domain-filters' + +// Helper to extract the query string and bind vars from an aql result, +// stripping the accumulated prefix so assertions stay readable. +function parse(result) { + return { + query: result.query, + bindVars: result.bindVars, + } +} + +// ─── Empty / no-op cases ──────────────────────────────────────────────────── + +describe('buildDomainFilters – empty / no-op', () => { + it('returns an empty aql fragment when filters is undefined', () => { + const result = buildDomainFilters({}) + expect(result.query).toBe('') + expect(result.bindVars).toEqual({}) + }) + + it('returns an empty aql fragment when filters is null', () => { + const result = buildDomainFilters({ filters: null }) + expect(result.query).toBe('') + expect(result.bindVars).toEqual({}) + }) + + it('returns an empty aql fragment when filters is an empty array', () => { + const result = buildDomainFilters({ filters: [] }) + expect(result.query).toBe('') + expect(result.bindVars).toEqual({}) + }) +}) + +// ─── Status filters ───────────────────────────────────────────────────────── + +describe('buildDomainFilters – status filters (==)', () => { + const STATUS_CASES = [ + ['dmarc-status', 'v.status.dmarc'], + ['dkim-status', 'v.status.dkim'], + ['https-status', 'v.status.https'], + ['spf-status', 'v.status.spf'], + ['ciphers-status', 'v.status.ciphers'], + ['curves-status', 'v.status.curves'], + ['hsts-status', 'v.status.hsts'], + ['policy-status', 'v.status.policy'], + ['protocols-status', 'v.status.protocols'], + ['certificates-status', 'v.status.certificates'], + ] + + test.each(STATUS_CASES)('%s maps to %s with == comparison', (filterCategory, aqlField) => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [{ filterCategory, comparison: '==', filterValue: 'pass' }], + }), + ) + expect(query).toContain(`FILTER ${aqlField} ==`) + expect(Object.values(bindVars)).toContain('pass') + }) +}) + +describe('buildDomainFilters – status filters (!=)', () => { + it('uses != comparison operator for dmarc-status', () => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'dmarc-status', comparison: '!=', filterValue: 'fail' }], + }), + ) + expect(query).toContain('FILTER v.status.dmarc !=') + expect(Object.values(bindVars)).toContain('fail') + }) + + it('uses != comparison operator for https-status', () => { + const { query } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'https-status', comparison: '!=', filterValue: 'info' }], + }), + ) + expect(query).toContain('FILTER v.status.https !=') + }) +}) + +// ─── Tag filters – mapped fields ───────────────────────────────────────────── + +describe('buildDomainFilters – tags filter (mapped fields)', () => { + const TAG_CASES = [ + ['archived', 'v.archived', true], + ['nxdomain', 'v.rcode', 'NXDOMAIN'], + ['blocked', 'v.blocked', true], + ['wildcard-sibling', 'v.wildcardSibling', true], + ['wildcard-entry', 'v.wildcardEntry', true], + ['scan-pending', 'v.webScanPending', true], + ['has-entrust-certificate', 'v.hasEntrustCertificate', true], + ['cve-detected', 'v.cveDetected', true], + ['cvd-enrolled', 'v.cvdEnrollment.status', 'enrolled'], + ['cvd-pending', 'v.cvdEnrollment.status', 'pending'], + ] + + test.each(TAG_CASES)('tag value "%s" filters on field %s', (filterValue, aqlField) => { + const { query } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'tags', comparison: '==', filterValue }], + }), + ) + expect(query).toContain(`FILTER ${aqlField}`) + }) + + it('applies != comparison for a mapped tag (archived)', () => { + const { query } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'tags', comparison: '!=', filterValue: 'archived' }], + }), + ) + expect(query).toContain('FILTER v.archived !=') + }) +}) + +describe('buildDomainFilters – tags filter (unmapped / free-form)', () => { + it('falls back to POSITION(e.tags, ...) for an unknown tag value', () => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'tags', comparison: '==', filterValue: 'some-custom-tag' }], + }), + ) + expect(query).toContain('FILTER POSITION(e.tags,') + expect(query).toContain('== true') + expect(Object.values(bindVars)).toContain('some-custom-tag') + }) + + it('uses != with POSITION for an unknown tag with != comparison', () => { + const { query } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'tags', comparison: '!=', filterValue: 'another-tag' }], + }), + ) + expect(query).toContain('POSITION(e.tags,') + expect(query).toContain('!= true') + }) +}) + +// ─── Other filter categories ───────────────────────────────────────────────── + +describe('buildDomainFilters – asset-state filter', () => { + it('filters on e.assetState with == comparison', () => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'asset-state', comparison: '==', filterValue: 'approved' }], + }), + ) + expect(query).toContain('FILTER e.assetState ==') + expect(Object.values(bindVars)).toContain('approved') + }) + + it('filters on e.assetState with != comparison', () => { + const { query } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'asset-state', comparison: '!=', filterValue: 'hidden' }], + }), + ) + expect(query).toContain('FILTER e.assetState !=') + }) +}) + +describe('buildDomainFilters – guidance-tag filter', () => { + it('filters using POSITION(negativeTags, ...) with == comparison', () => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'guidance-tag', comparison: '==', filterValue: 'weak-cipher' }], + }), + ) + expect(query).toContain('FILTER POSITION(negativeTags,') + expect(query).toContain('== true') + expect(Object.values(bindVars)).toContain('weak-cipher') + }) + + it('filters using POSITION(negativeTags, ...) with != comparison', () => { + const { query } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'guidance-tag', comparison: '!=', filterValue: 'weak-cipher' }], + }), + ) + expect(query).toContain('FILTER POSITION(negativeTags,') + expect(query).toContain('!= true') + }) +}) + +describe('buildDomainFilters – dmarc-phase filter', () => { + it('filters on v.phase with == comparison', () => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'dmarc-phase', comparison: '==', filterValue: 'assess' }], + }), + ) + expect(query).toContain('FILTER v.phase ==') + expect(Object.values(bindVars)).toContain('assess') + }) + + it('filters on v.phase with != comparison', () => { + const { query } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'dmarc-phase', comparison: '!=', filterValue: 'deploy' }], + }), + ) + expect(query).toContain('FILTER v.phase !=') + }) +}) + +describe('buildDomainFilters – unknown filterCategory', () => { + it('silently skips an unrecognised filter category', () => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [{ filterCategory: 'totally-unknown', comparison: '==', filterValue: 'x' }], + }), + ) + // The accumulated fragment should be empty — nothing appended + expect(query).toBe('') + expect(bindVars).toEqual({}) + }) +}) + +// ─── Multiple filters combined ─────────────────────────────────────────────── + +describe('buildDomainFilters – multiple filters', () => { + it('accumulates all filters into a single AQL fragment', () => { + const { query, bindVars } = parse( + buildDomainFilters({ + filters: [ + { filterCategory: 'dmarc-status', comparison: '==', filterValue: 'pass' }, + { filterCategory: 'https-status', comparison: '!=', filterValue: 'fail' }, + { filterCategory: 'asset-state', comparison: '==', filterValue: 'approved' }, + ], + }), + ) + expect(query).toContain('FILTER v.status.dmarc ==') + expect(query).toContain('FILTER v.status.https !=') + expect(query).toContain('FILTER e.assetState ==') + expect(Object.values(bindVars)).toContain('pass') + expect(Object.values(bindVars)).toContain('fail') + expect(Object.values(bindVars)).toContain('approved') + }) + + it('combines a mapped tag filter with a status filter', () => { + const { query } = parse( + buildDomainFilters({ + filters: [ + { filterCategory: 'tags', comparison: '==', filterValue: 'blocked' }, + { filterCategory: 'spf-status', comparison: '==', filterValue: 'pass' }, + ], + }), + ) + expect(query).toContain('FILTER v.blocked') + expect(query).toContain('FILTER v.status.spf') + }) + + it('handles an unknown filter mixed with a valid one without losing the valid one', () => { + const { query } = parse( + buildDomainFilters({ + filters: [ + { filterCategory: 'dmarc-phase', comparison: '==', filterValue: 'assess' }, + { filterCategory: 'not-a-real-category', comparison: '==', filterValue: 'nope' }, + ], + }), + ) + expect(query).toContain('FILTER v.phase ==') + // The unknown category should not add anything extra + expect(query).not.toContain('nope') + }) +}) diff --git a/api/src/domain/helpers/build-domain-filters.js b/api/src/domain/helpers/build-domain-filters.js new file mode 100644 index 0000000000..e43039d971 --- /dev/null +++ b/api/src/domain/helpers/build-domain-filters.js @@ -0,0 +1,121 @@ +import { aql } from 'arangojs' + +// Maps filter categories to their AQL field paths +const STATUS_FILTER_MAP = { + 'dmarc-status': 'v.status.dmarc', + 'dkim-status': 'v.status.dkim', + 'https-status': 'v.status.https', + 'spf-status': 'v.status.spf', + 'ciphers-status': 'v.status.ciphers', + 'curves-status': 'v.status.curves', + 'hsts-status': 'v.status.hsts', + 'policy-status': 'v.status.policy', + 'protocols-status': 'v.status.protocols', + 'certificates-status': 'v.status.certificates', +} + +// Maps tag filter values to { field, value } pairs for direct field comparisons +const TAG_FIELD_MAP = { + archived: { field: 'v.archived', value: true }, + nxdomain: { field: 'v.rcode', value: 'NXDOMAIN' }, + blocked: { field: 'v.blocked', value: true }, + 'wildcard-sibling': { field: 'v.wildcardSibling', value: true }, + 'wildcard-entry': { field: 'v.wildcardEntry', value: true }, + 'scan-pending': { field: 'v.webScanPending', value: true }, + 'has-entrust-certificate': { field: 'v.hasEntrustCertificate', value: true }, + 'cve-detected': { field: 'v.cveDetected', value: true }, + 'cvd-enrolled': { field: 'v.cvdEnrollment.status', value: 'enrolled' }, + 'cvd-pending': { field: 'v.cvdEnrollment.status', value: 'pending' }, + 'cvd-deny': { field: 'v.cvdEnrollment.status', value: 'deny' }, +} + +function buildComparison(comparison) { + return comparison === '==' ? aql`==` : aql`!=` +} + +function buildStatusFilter(accumulated, field, comparison, filterValue) { + // AQL doesn't support dynamic field access, so we need a switch here. + // The field string is only ever sourced from STATUS_FILTER_MAP above, never user input. + switch (field) { + case 'v.status.dmarc': + return aql`${accumulated} FILTER v.status.dmarc ${comparison} ${filterValue}` + case 'v.status.dkim': + return aql`${accumulated} FILTER v.status.dkim ${comparison} ${filterValue}` + case 'v.status.https': + return aql`${accumulated} FILTER v.status.https ${comparison} ${filterValue}` + case 'v.status.spf': + return aql`${accumulated} FILTER v.status.spf ${comparison} ${filterValue}` + case 'v.status.ciphers': + return aql`${accumulated} FILTER v.status.ciphers ${comparison} ${filterValue}` + case 'v.status.curves': + return aql`${accumulated} FILTER v.status.curves ${comparison} ${filterValue}` + case 'v.status.hsts': + return aql`${accumulated} FILTER v.status.hsts ${comparison} ${filterValue}` + case 'v.status.policy': + return aql`${accumulated} FILTER v.status.policy ${comparison} ${filterValue}` + case 'v.status.protocols': + return aql`${accumulated} FILTER v.status.protocols ${comparison} ${filterValue}` + case 'v.status.certificates': + return aql`${accumulated} FILTER v.status.certificates ${comparison} ${filterValue}` + default: + return accumulated + } +} + +function buildTagFilter(accumulated, comparison, filterValue) { + const mapped = TAG_FIELD_MAP[filterValue] + + if (!mapped) { + return aql`${accumulated} FILTER POSITION(e.tags, ${filterValue}) ${comparison} true` + } + + // Same dynamic field problem — switch on the known field paths from TAG_FIELD_MAP + switch (mapped.field) { + case 'v.archived': + return aql`${accumulated} FILTER v.archived ${comparison} ${mapped.value}` + case 'v.rcode': + return aql`${accumulated} FILTER v.rcode ${comparison} ${mapped.value}` + case 'v.blocked': + return aql`${accumulated} FILTER v.blocked ${comparison} ${mapped.value}` + case 'v.wildcardSibling': + return aql`${accumulated} FILTER v.wildcardSibling ${comparison} ${mapped.value}` + case 'v.wildcardEntry': + return aql`${accumulated} FILTER v.wildcardEntry ${comparison} ${mapped.value}` + case 'v.webScanPending': + return aql`${accumulated} FILTER v.webScanPending ${comparison} ${mapped.value}` + case 'v.hasEntrustCertificate': + return aql`${accumulated} FILTER v.hasEntrustCertificate ${comparison} ${mapped.value}` + case 'v.cveDetected': + return aql`${accumulated} FILTER v.cveDetected ${comparison} ${mapped.value}` + case 'v.cvdEnrollment.status': + return aql`${accumulated} FILTER v.cvdEnrollment.status ${comparison} ${mapped.value}` + default: + return accumulated + } +} + +function buildSingleFilter(accumulated, { filterCategory, comparison, filterValue }) { + const cmp = buildComparison(comparison) + + if (filterCategory in STATUS_FILTER_MAP) { + return buildStatusFilter(accumulated, STATUS_FILTER_MAP[filterCategory], cmp, filterValue) + } + + switch (filterCategory) { + case 'tags': + return buildTagFilter(accumulated, cmp, filterValue) + case 'asset-state': + return aql`${accumulated} FILTER e.assetState ${cmp} ${filterValue}` + case 'guidance-tag': + return aql`${accumulated} FILTER POSITION(negativeTags, ${filterValue}) ${cmp} true` + case 'dmarc-phase': + return aql`${accumulated} FILTER v.phase ${cmp} ${filterValue}` + default: + return accumulated + } +} + +export function buildDomainFilters({ filters }) { + if (!filters?.length) return aql`` + return filters.reduce(buildSingleFilter, aql``) +} diff --git a/api/src/domain/helpers/index.js b/api/src/domain/helpers/index.js new file mode 100644 index 0000000000..2e6a27b84a --- /dev/null +++ b/api/src/domain/helpers/index.js @@ -0,0 +1 @@ +export * from './build-domain-filters' diff --git a/api/src/domain/loaders/load-domain-connections-by-organizations-id.js b/api/src/domain/loaders/load-domain-connections-by-organizations-id.js index b8dde82124..14dd6d7a55 100644 --- a/api/src/domain/loaders/load-domain-connections-by-organizations-id.js +++ b/api/src/domain/loaders/load-domain-connections-by-organizations-id.js @@ -1,6 +1,7 @@ import { aql } from 'arangojs' import { fromGlobalId, toGlobalId } from 'graphql-relay' import { t } from '@lingui/macro' +import { buildDomainFilters } from '../helpers' export const loadDomainConnectionsByOrgId = ({ query, userKey, cleanseInput, i18n, auth: { loginRequiredBool } }) => @@ -288,129 +289,7 @@ export const loadDomainConnectionsByOrgId = } } - let domainFilters = aql`` - if (typeof filters !== 'undefined') { - filters.forEach(({ filterCategory, comparison, filterValue }) => { - if (comparison === '==') { - comparison = aql`==` - } else { - comparison = aql`!=` - } - if (filterCategory === 'dmarc-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.dmarc ${comparison} ${filterValue} - ` - } else if (filterCategory === 'dkim-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.dkim ${comparison} ${filterValue} - ` - } else if (filterCategory === 'https-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.https ${comparison} ${filterValue} - ` - } else if (filterCategory === 'spf-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.spf ${comparison} ${filterValue} - ` - } else if (filterCategory === 'ciphers-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.ciphers ${comparison} ${filterValue} - ` - } else if (filterCategory === 'curves-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.curves ${comparison} ${filterValue} - ` - } else if (filterCategory === 'hsts-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.hsts ${comparison} ${filterValue} - ` - } else if (filterCategory === 'policy-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.policy ${comparison} ${filterValue} - ` - } else if (filterCategory === 'protocols-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.protocols ${comparison} ${filterValue} - ` - } else if (filterCategory === 'certificates-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.certificates ${comparison} ${filterValue} - ` - } else if (filterCategory === 'tags') { - if (filterValue === 'archived') { - domainFilters = aql` - ${domainFilters} - FILTER v.archived ${comparison} true - ` - } else if (filterValue === 'nxdomain') { - domainFilters = aql` - ${domainFilters} - FILTER v.rcode ${comparison} "NXDOMAIN" - ` - } else if (filterValue === 'blocked') { - domainFilters = aql` - ${domainFilters} - FILTER v.blocked ${comparison} true - ` - } else if (filterValue === 'wildcard-sibling') { - domainFilters = aql` - ${domainFilters} - FILTER v.wildcardSibling ${comparison} true - ` - } else if (filterValue === 'wildcard-entry') { - domainFilters = aql` - ${domainFilters} - FILTER v.wildcardEntry ${comparison} true - ` - } else if (filterValue === 'scan-pending') { - domainFilters = aql` - ${domainFilters} - FILTER v.webScanPending ${comparison} true - ` - } else if (filterValue === 'has-entrust-certificate') { - domainFilters = aql` - ${domainFilters} - FILTER v.hasEntrustCertificate ${comparison} true - ` - } else if (filterValue === 'cve-detected') { - domainFilters = aql` - ${domainFilters} - FILTER v.cveDetected ${comparison} true - ` - } else { - domainFilters = aql` - ${domainFilters} - FILTER POSITION(e.tags, ${filterValue}) ${comparison} true - ` - } - } else if (filterCategory === 'asset-state') { - domainFilters = aql` - ${domainFilters} - FILTER e.assetState ${comparison} ${filterValue} - ` - } else if (filterCategory === 'guidance-tag') { - domainFilters = aql` - ${domainFilters} - FILTER POSITION(negativeTags, ${filterValue}) ${comparison} true - ` - } else if (filterCategory === 'dmarc-phase') { - domainFilters = aql` - ${domainFilters} - FILTER v.phase ${comparison} ${filterValue} - ` - } - }) - } + const domainFilters = buildDomainFilters({ filters }) let domainQuery = aql`` let loopString = aql`FOR domain IN collectedDomains` diff --git a/api/src/domain/loaders/load-domain-connections-by-user-id.js b/api/src/domain/loaders/load-domain-connections-by-user-id.js index 392648a354..b15b39d901 100644 --- a/api/src/domain/loaders/load-domain-connections-by-user-id.js +++ b/api/src/domain/loaders/load-domain-connections-by-user-id.js @@ -1,6 +1,7 @@ import { aql } from 'arangojs' import { fromGlobalId, toGlobalId } from 'graphql-relay' import { t } from '@lingui/macro' +import { buildDomainFilters } from '../helpers' export const loadDomainConnectionsByUserId = ({ query, userKey, cleanseInput, i18n, auth: { loginRequiredBool } }) => @@ -315,114 +316,7 @@ export const loadDomainConnectionsByUserId = } } - let domainFilters = aql`` - if (typeof filters !== 'undefined') { - filters.forEach(({ filterCategory, comparison, filterValue }) => { - if (comparison === '==') { - comparison = aql`==` - } else { - comparison = aql`!=` - } - if (filterCategory === 'dmarc-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.dmarc ${comparison} ${filterValue} - ` - } else if (filterCategory === 'dkim-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.dkim ${comparison} ${filterValue} - ` - } else if (filterCategory === 'https-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.https ${comparison} ${filterValue} - ` - } else if (filterCategory === 'spf-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.spf ${comparison} ${filterValue} - ` - } else if (filterCategory === 'ciphers-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.ciphers ${comparison} ${filterValue} - ` - } else if (filterCategory === 'curves-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.curves ${comparison} ${filterValue} - ` - } else if (filterCategory === 'hsts-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.hsts ${comparison} ${filterValue} - ` - } else if (filterCategory === 'policy-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.policy ${comparison} ${filterValue} - ` - } else if (filterCategory === 'protocols-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.protocols ${comparison} ${filterValue} - ` - } else if (filterCategory === 'certificates-status') { - domainFilters = aql` - ${domainFilters} - FILTER v.status.certificates ${comparison} ${filterValue} - ` - } else if (filterCategory === 'tags') { - if (filterValue === 'archived') { - domainFilters = aql` - ${domainFilters} - FILTER v.archived ${comparison} true - ` - } else if (filterValue === 'nxdomain') { - domainFilters = aql` - ${domainFilters} - FILTER v.rcode ${comparison} "NXDOMAIN" - ` - } else if (filterValue === 'blocked') { - domainFilters = aql` - ${domainFilters} - FILTER v.blocked ${comparison} true - ` - } else if (filterValue === 'wildcard-sibling') { - domainFilters = aql` - ${domainFilters} - FILTER v.wildcardSibling ${comparison} true - ` - } else if (filterValue === 'wildcard-entry') { - domainFilters = aql` - ${domainFilters} - FILTER v.wildcardEntry ${comparison} true - ` - } else if (filterValue === 'scan-pending') { - domainFilters = aql` - ${domainFilters} - FILTER v.webScanPending ${comparison} true - ` - } else if (filterValue === 'has-entrust-certificate') { - domainFilters = aql` - ${domainFilters} - FILTER v.hasEntrustCertificate ${comparison} true - ` - } else if (filterValue === 'cve-detected') { - domainFilters = aql` - ${domainFilters} - FILTER v.cveDetected ${comparison} true - ` - } - } else if (filterCategory === 'dmarc-phase') { - domainFilters = aql` - ${domainFilters} - FILTER v.phase ${comparison} ${filterValue} - ` - } - }) - } + const domainFilters = buildDomainFilters({ filters }) let domainKeysQuery if (myTracker) { diff --git a/api/src/domain/mutations/__tests__/create-domain.test.js b/api/src/domain/mutations/__tests__/create-domain.test.js index 71e9b279f4..26c60b9e6b 100644 --- a/api/src/domain/mutations/__tests__/create-domain.test.js +++ b/api/src/domain/mutations/__tests__/create-domain.test.js @@ -17,9 +17,11 @@ import { verifiedRequired, tfaRequired, checkDomainPermission, + AuthDataSource, } from '../../../auth' import { loadDkimSelectorsByDomainId, loadDomainByDomain } from '../../loaders' import { loadOrgByKey, loadOrgConnectionsByDomainId } from '../../../organization/loaders' +import { OrganizationDataSource } from '../../../organization/data-source' import { loadUserByKey } from '../../../user/loaders' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -33,6 +35,20 @@ describe('create a domain', () => { const mockedInfo = (output) => consoleOutput.push(output) const mockedWarn = (output) => consoleOutput.push(output) const mockedError = (output) => consoleOutput.push(output) + + const i18n = setupI18n({ + locale: 'en', + localeData: { + en: { plurals: {} }, + fr: { plurals: {} }, + }, + locales: ['en', 'fr'], + messages: { + en: englishMessages.messages, + fr: frenchMessages.messages, + }, + }) + beforeAll(async () => { console.info = mockedInfo console.warn = mockedWarn @@ -47,18 +63,6 @@ describe('create a domain', () => { consoleOutput.length = 0 }) describe('given a successful domain creation', () => { - const i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) beforeAll(async () => { ;({ query, drop, truncate, collections, transaction } = await ensure({ variables: { @@ -204,6 +208,19 @@ describe('create a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + loginRequiredBool: true, + transaction, + collections: collectionNames, + }), + }, loaders: { loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ query, @@ -365,6 +382,19 @@ describe('create a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + loginRequiredBool: true, + transaction, + collections: collectionNames, + }), + }, loaders: { loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ query, @@ -502,6 +532,19 @@ describe('create a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + loginRequiredBool: true, + transaction, + collections: collectionNames, + }), + }, loaders: { loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ query, @@ -679,6 +722,19 @@ describe('create a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + loginRequiredBool: true, + transaction, + collections: collectionNames, + }), + }, loaders: { loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ query, @@ -819,6 +875,19 @@ describe('create a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + loginRequiredBool: true, + transaction, + collections: collectionNames, + }), + }, loaders: { loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ query, @@ -960,6 +1029,19 @@ describe('create a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + loginRequiredBool: true, + transaction, + collections: collectionNames, + }), + }, loaders: { loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ query, @@ -1030,30 +1112,28 @@ describe('create a domain', () => { }) describe('given an unsuccessful domain creation', () => { let i18n - describe('request language is english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) + beforeAll(() => { + i18n = setupI18n({ + locale: 'en', + localeData: { + en: { plurals: {} }, + fr: { plurals: {} }, + }, + locales: ['en', 'fr'], + messages: { + en: englishMessages.messages, + fr: frenchMessages.messages, + }, }) - describe('org does not exist', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` + }) + describe('org does not exist', () => { + it('returns an error', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( - input: { orgId: "b3JnYW5pemF0aW9uOjE=", domain: "test.gc.ca" - assetState: APPROVED } + input: { orgId: "b3JnYW5pemF0aW9uOjE=", domain: "test.gc.ca", assetState: APPROVED, cvdEnrollment: { status: ENROLLED } } ) { result { ... on Domain { @@ -1068,6 +1148,9 @@ describe('create a domain', () => { spf ssl } + cvdEnrollment { + status + } organizations(first: 5) { edges { node { @@ -1085,74 +1168,149 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ + i18n, + userKey: user._key, + query, + }), + checkPermission: jest.fn(), + saltedHash: jest.fn(), + userRequired: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), }, - query, - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn(), - saltedHash: jest.fn(), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), + loadOrgByKey: { + load: jest.fn().mockReturnValue(undefined), }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), }, - validators: { cleanseInput, slugify }, }, - }) + validators: { cleanseInput, slugify }, + }, + }) - const error = { - data: { - createDomain: { - result: { - code: 400, - description: 'Unable to create domain in unknown organization.', - }, + const error = { + data: { + createDomain: { + result: { + code: 400, + description: 'Unable to create domain in unknown organization.', }, }, - } + }, + } - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to create a domain to an organization: 1 that does not exist.`, - ]) + expect(response).toEqual(error) + expect(consoleOutput).toEqual([ + `User: 123 attempted to create a domain to an organization: 1 that does not exist.`, + ]) + }) + + it('returns the domain with cvdEnrollment status not-enrolled when not provided', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + createDomain( + input: { orgId: "b3JnYW5pemF0aW9uOjE=", domain: "test.gc.ca", assetState: APPROVED } + ) { + result { + ... on Domain { + cvdEnrollment { + status + } + } + } + } + } + `, + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ + i18n, + userKey: user._key, + query, + }), + checkPermission: jest.fn(), + saltedHash: jest.fn(), + userRequired: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue(undefined), + }, + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, }) + // Should default to not-enrolled + if ( + response.data && + response.data.createDomain && + response.data.createDomain.result && + response.data.createDomain.result.cvdEnrollment + ) { + expect(response.data.createDomain.result.cvdEnrollment.status).toBe('not-enrolled') + } }) - describe('user does not belong to organization', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` + }) + }) + describe('user does not belong to organization', () => { + it('returns an error', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -1191,76 +1349,76 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query, + collections: collectionNames, + transaction, + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, + userKey: user._key, query, - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue(undefined), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, + }), + checkPermission: jest.fn().mockReturnValue(undefined), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), }, - }) - - const error = { - data: { - createDomain: { - result: { - code: 400, - description: 'Permission Denied: Please contact organization user for help with creating domain.', - }, - }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to create a domain in: treasury-board-secretariat, however they do not have permission to do so.`, - ]) - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, }) - describe('the domain already exists in the given organization', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` + + const error = { + data: { + createDomain: { + result: { + code: 400, + description: 'Permission Denied: Please contact organization user for help with creating domain.', + }, + }, + }, + } + + expect(response).toEqual(error) + expect(consoleOutput).toEqual([ + `User: 123 attempted to create a domain in: treasury-board-secretariat, however they do not have permission to do so.`, + ]) + }) + }) + describe('the domain already exists in the given organization', () => { + it('returns an error', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -1299,79 +1457,79 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockReturnValue({}), + }), + collections: collectionNames, + transaction, + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue({}), + userKey: user._key, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = { - data: { - createDomain: { - result: { - code: 400, - description: 'Unable to create domain, organization has already claimed it.', - }, - }, + const error = { + data: { + createDomain: { + result: { + code: 400, + description: 'Unable to create domain, organization has already claimed it.', }, - } + }, + }, + } - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to create a domain for: treasury-board-secretariat, however that org already has that domain claimed.`, - ]) - }) - }) - describe('database error occurs', () => { - describe('when checking to see if org already contains domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + expect(response).toEqual(error) + expect(consoleOutput).toEqual([ + `User: 123 attempted to create a domain for: treasury-board-secretariat, however that org already has that domain claimed.`, + ]) + }) + }) + describe('database error occurs', () => { + describe('when checking to see if org already contains domain', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -1410,69 +1568,69 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), + collections: collectionNames, + transaction, + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, + userKey: user._key, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', + }), + }, + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), }, - }) + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Unable to create domain. Please try again.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred while running check to see if domain already exists in an org: Error: Database error occurred.`, - ]) - }) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Database error occurred while running check to see if domain already exists in an org: Error: Database error occurred.`, + ]) }) - describe('cursor error occurs', () => { - describe('when checking to see if org already contains domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + }) + }) + describe('cursor error occurs', () => { + describe('when checking to see if org already contains domain', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -1511,69 +1669,69 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockRejectedValue(new Error('Cursor error occurred.')), + }), + collections: collectionNames, + transaction, + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockRejectedValue(new Error('Cursor error occurred.')), + userKey: user._key, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Unable to create domain. Please try again.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred while running check to see if domain already exists in an org: Error: Cursor error occurred.`, - ]) - }) - }) - describe('when gathering inserted domain', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Cursor error occurred while running check to see if domain already exists in an org: Error: Cursor error occurred.`, + ]) + }) + }) + describe('when gathering inserted domain', () => { + it('throws an error', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -1612,77 +1770,77 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockReturnValue(undefined), + }), + collections: collectionNames, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValueOnce({ + next: jest.fn().mockRejectedValue(new Error('cursor error')), + }), + abort: jest.fn(), + }), + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce({ - next: jest.fn().mockRejectedValue(new Error('cursor error')), - }), - abort: jest.fn(), + userKey: user._key, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Unable to create domain. Please try again.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred for user: 123 when inserting new domain: Error: cursor error`, - ]) - }) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Cursor error occurred for user: 123 when inserting new domain: Error: cursor error`, + ]) }) - describe('transaction step error occurs', () => { - describe('when creating a new domain', () => { - describe('when inserting new domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + }) + }) + describe('transaction step error occurs', () => { + describe('when creating a new domain', () => { + describe('when inserting new domain', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -1721,799 +1879,24 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Unable to create domain. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain: Error: trx step error`, - ]) - }) - }) - describe('when inserting new edge', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({ - next: jest.fn(), - }) - .mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Unable to create domain. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain edge: Error: trx step error`, - ]) - }) - }) - }) - describe('when domain already exists', () => { - describe('when upserting domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValueOnce(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn().mockReturnValue({ - domain: 'domain.ca', - selectors: [], - status: {}, - lastRan: '', - }), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Unable to create domain. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain: Error: trx step error`, - ]) - }) - }) - describe('when inserting edge to new org', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValueOnce(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({ next: jest.fn().mockReturnValue() }) - .mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: 123, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: 123, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn().mockReturnValue({ - domain: 'domain.ca', - selectors: [], - status: {}, - lastRan: '', - }), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Unable to create domain. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain edge: Error: trx step error`, - ]) - }) - }) - }) - }) - describe('transaction commit error occurs', () => { - describe('when committing transaction', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({ next: jest.fn().mockReturnValue() }), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: 123, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: 123, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn().mockReturnValue({ - domain: 'domain.ca', - selectors: [], - status: {}, - lastRan: '', - }), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Unable to create domain. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction commit error occurred while user: 123 was creating domain: Error: trx commit error`, - ]) - }) - }) - }) - }) - describe('request language is french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('org does not exist', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { orgId: "b3JnYW5pemF0aW9uOjE=", domain: "test.gc.ca" - assetState: APPROVED } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn(), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = { - data: { - createDomain: { - result: { - code: 400, - description: 'Impossible de créer un domaine dans une organisation inconnue.', - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to create a domain to an organization: 1 that does not exist.`, - ]) - }) - }) - describe('user does not belong to organization', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue(undefined), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = { - data: { - createDomain: { - result: { - code: 400, - description: - "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide sur la création du domaine.", - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to create a domain in: treasury-board-secretariat, however they do not have permission to do so.`, - ]) - }) - }) - describe('the domain already exists in the given organization', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue({}), - }), - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockReturnValue(undefined), + }), + collections: collectionNames, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('trx step error')), + abort: jest.fn(), + }), + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, userKey: user._key, query, @@ -2531,462 +1914,37 @@ describe('create a domain', () => { cleanseInput, i18n, auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = { - data: { - createDomain: { - result: { - code: 400, - description: "Impossible de créer le domaine, l'organisation l'a déjà réclamé.", - }, - }, - }, - } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to create a domain for: treasury-board-secretariat, however that org already has that domain claimed.`, - ]) - }) - }) - describe('database error occurs', () => { - describe('when checking to see if org already contains domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred while running check to see if domain already exists in an org: Error: Database error occurred.`, - ]) - }) - }) - }) - describe('cursor error occurs', () => { - describe('when checking to see if org already contains domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockRejectedValue(new Error('Cursor error occurred.')), - }), - collections: collectionNames, - transaction, - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred while running check to see if domain already exists in an org: Error: Cursor error occurred.`, - ]) - }) - }) - describe('when gathering inserted domain', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce({ - next: jest.fn().mockRejectedValue(new Error('cursor error')), - }), - abort: jest.fn(), - }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: 123, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: 123, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, - }, - }) - - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred for user: 123 when inserting new domain: Error: cursor error`, - ]) - }) - }) - }) - describe('transaction step error occurs', () => { - describe('when creating a new domain', () => { - describe('when inserting new domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createDomain( - input: { - orgId: "${toGlobalId('organization', 123)}" - domain: "test.gc.ca" - assetState: APPROVED - } - ) { - result { - ... on Domain { - id - domain - lastRan - selectors - status { - dkim - dmarc - https - spf - ssl - } - organizations(first: 5) { - edges { - node { - id - name - } - } - } - } - ... on DomainError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), + }), + loadDomainByDomain: { + load: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain: Error: trx step error`, - ]) - }) - }) - describe('when inserting new edge', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Transaction step error occurred for user: 123 when inserting new domain: Error: trx step error`, + ]) + }) + }) + describe('when inserting new edge', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -3025,79 +1983,79 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockReturnValue(undefined), + }), + collections: collectionNames, + transaction: jest.fn().mockReturnValue({ + step: jest + .fn() + .mockReturnValueOnce({ + next: jest.fn(), + }) + .mockRejectedValue(new Error('trx step error')), + abort: jest.fn(), + }), + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue(undefined), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({ - next: jest.fn(), - }) - .mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), + userKey: user._key, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn(), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain edge: Error: trx step error`, - ]) - }) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Transaction step error occurred for user: 123 when inserting new domain edge: Error: trx step error`, + ]) }) - describe('when domain already exists', () => { - describe('when upserting domain', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + }) + }) + describe('when domain already exists', () => { + describe('when upserting domain', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -3136,77 +2094,77 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockReturnValueOnce(undefined), + }), + collections: collectionNames, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockRejectedValue(new Error('trx step error')), + abort: jest.fn(), + }), + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValueOnce(undefined), + userKey: user._key, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: user._key, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn().mockReturnValue({ + domain: 'domain.ca', + selectors: [], + status: {}, + lastRan: '', }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: user._key, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: user._key, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn().mockReturnValue({ - domain: 'domain.ca', - selectors: [], - status: {}, - lastRan: '', - }), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain: Error: trx step error`, - ]) - }) - }) - describe('when inserting edge to new org', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Transaction step error occurred for user: 123 when inserting new domain: Error: trx step error`, + ]) + }) + }) + describe('when inserting edge to new org', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -3245,83 +2203,83 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockReturnValueOnce(undefined), + }), + collections: collectionNames, + transaction: jest.fn().mockReturnValue({ + step: jest + .fn() + .mockReturnValueOnce({ next: jest.fn().mockReturnValue() }) + .mockRejectedValue(new Error('trx step error')), + abort: jest.fn(), + }), + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValueOnce(undefined), + userKey: 123, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: 123, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn().mockReturnValue({ + domain: 'domain.ca', + selectors: [], + status: {}, + lastRan: '', }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({ next: jest.fn().mockReturnValueOnce(undefined) }) - .mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: 123, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: 123, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn().mockReturnValue({ - domain: 'domain.ca', - selectors: [], - status: {}, - lastRan: '', - }), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction step error occurred for user: 123 when inserting new domain edge: Error: trx step error`, - ]) - }) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Transaction step error occurred for user: 123 when inserting new domain edge: Error: trx step error`, + ]) }) }) - describe('transaction commit error occurs', () => { - describe('when committing transaction', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` + }) + }) + describe('transaction commit error occurs', () => { + describe('when committing transaction', () => { + it('returns an error message', async () => { + const response = await graphql({ + schema, + source: ` mutation { createDomain( input: { @@ -3360,73 +2318,71 @@ describe('create a domain', () => { } } `, - rootValue: null, - contextValue: { + rootValue: null, + contextValue: { + i18n, + request: { + language: 'en', + }, + query: jest.fn().mockReturnValue({ + next: jest.fn().mockReturnValue(undefined), + }), + collections: collectionNames, + transaction: jest.fn().mockReturnValue({ + step: jest.fn().mockReturnValue({ next: jest.fn().mockReturnValue() }), + commit: jest.fn().mockRejectedValue(new Error('trx commit error')), + abort: jest.fn(), + }), + userKey: 123, + publish: jest.fn(), + auth: { + checkDomainPermission: checkDomainPermission({ i18n, - request: { - language: 'en', - }, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValueOnce(undefined), + userKey: 123, + query, + }), + checkPermission: jest.fn().mockReturnValue('admin'), + userRequired: jest.fn(), + saltedHash: jest.fn(), + verifiedRequired: jest.fn(), + tfaRequired: jest.fn(), + }, + loaders: { + loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ + query, + userKey: 123, + cleanseInput, + i18n, + auth: { loginRequiredBool: true }, + }), + loadDomainByDomain: { + load: jest.fn().mockReturnValue({ + domain: 'domain.ca', + selectors: [], + status: {}, + lastRan: '', }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({ next: jest.fn().mockReturnValueOnce(undefined) }), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), + }, + loadOrgByKey: { + load: jest.fn().mockReturnValue({ + slug: 'treasury-board-secretariat', }), - userKey: 123, - publish: jest.fn(), - auth: { - checkDomainPermission: checkDomainPermission({ - i18n, - userKey: 123, - query, - }), - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn(), - saltedHash: jest.fn(), - verifiedRequired: jest.fn(), - tfaRequired: jest.fn(), - }, - loaders: { - loadDkimSelectorsByDomainId: loadDkimSelectorsByDomainId({ - query, - userKey: 123, - cleanseInput, - i18n, - auth: { loginRequiredBool: true }, - }), - loadDomainByDomain: { - load: jest.fn().mockReturnValue({ - domain: 'domain.ca', - selectors: [], - status: {}, - lastRan: '', - }), - }, - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - slug: 'treasury-board-secretariat', - }), - }, - loadOrgConnectionsByDomainId: jest.fn(), - loadUserByKey: { - load: jest.fn(), - }, - }, - validators: { cleanseInput, slugify }, }, - }) + loadOrgConnectionsByDomainId: jest.fn(), + loadUserByKey: { + load: jest.fn(), + }, + }, + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Impossible de créer un domaine. Veuillez réessayer.')] + const error = [new GraphQLError('Unable to create domain. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction commit error occurred while user: 123 was creating domain: Error: trx commit error`, - ]) - }) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([ + `Transaction commit error occurred while user: 123 was creating domain: Error: trx commit error`, + ]) }) }) }) diff --git a/api/src/domain/mutations/__tests__/update-domain.test.js b/api/src/domain/mutations/__tests__/update-domain.test.js index e40488f213..f5e26e75ec 100644 --- a/api/src/domain/mutations/__tests__/update-domain.test.js +++ b/api/src/domain/mutations/__tests__/update-domain.test.js @@ -9,7 +9,14 @@ import { createMutationSchema } from '../../../mutation' import englishMessages from '../../../locale/en/messages' import frenchMessages from '../../../locale/fr/messages' import { cleanseInput, slugify } from '../../../validators' -import { checkPermission, userRequired, verifiedRequired, tfaRequired, checkDomainPermission } from '../../../auth' +import { + checkPermission, + userRequired, + verifiedRequired, + tfaRequired, + checkDomainPermission, + AuthDataSource, +} from '../../../auth' import { loadDkimSelectorsByDomainId, loadDomainByKey } from '../../loaders' import { loadOrgByKey } from '../../../organization/loaders' import { loadUserByKey } from '../../../user/loaders' @@ -181,6 +188,9 @@ describe('updating a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + }, validators: { cleanseInput, slugify, @@ -274,6 +284,9 @@ describe('updating a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + }, validators: { cleanseInput, slugify, @@ -367,6 +380,9 @@ describe('updating a domain', () => { verifiedRequired: verifiedRequired({}), tfaRequired: tfaRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + }, validators: { cleanseInput, slugify, diff --git a/api/src/domain/mutations/__tests__/update-domains-by-filters.test.js b/api/src/domain/mutations/__tests__/update-domains-by-filters.test.js index 8d5e910bbb..373aa89997 100644 --- a/api/src/domain/mutations/__tests__/update-domains-by-filters.test.js +++ b/api/src/domain/mutations/__tests__/update-domains-by-filters.test.js @@ -162,7 +162,6 @@ describe('updateDomainsByFilters mutation', () => { validators: { cleanseInput }, }, }) - console.log(response) expect(response.data.updateDomainsByFilters.result.status).toMatch( /Successfully updated 1 domain\(s\) in treasury-board-secretariat/, ) diff --git a/api/src/domain/mutations/create-domain.js b/api/src/domain/mutations/create-domain.js index 3b0d27a7e5..4460f8f55e 100644 --- a/api/src/domain/mutations/create-domain.js +++ b/api/src/domain/mutations/create-domain.js @@ -7,6 +7,8 @@ import { Domain } from '../../scalars' import { logActivity } from '../../audit-logs/mutations/log-activity' import { AssetStateEnums } from '../../enums' import { headers } from 'nats' +import { CvdEnrollmentInputOptions } from '../../additional-findings/input/cvd-enrollment-options' +import ac from '../../access-control' export const createDomain = new mutationWithClientMutationId({ name: 'CreateDomain', @@ -32,6 +34,11 @@ export const createDomain = new mutationWithClientMutationId({ description: 'Value that determines how the domain relates to the organization.', type: new GraphQLNonNull(AssetStateEnums), }, + cvdEnrollment: { + description: + 'The Coordinated Vulnerability Disclosure (CVD) enrollment details for this domain, including HackerOne integration status and CVSS requirements.', + type: CvdEnrollmentInputOptions, + }, }), outputFields: () => ({ result: { @@ -93,9 +100,11 @@ export const createDomain = new mutationWithClientMutationId({ if (typeof args.assetState !== 'undefined') { assetState = cleanseInput(args.assetState) } else { - assetState = '' + assetState = 'approved' } + const cvdEnrollment = args.cvdEnrollment || { status: 'not-enrolled' } + // Check to see if org exists const org = await loadOrgByKey.load(orgId) @@ -111,7 +120,7 @@ export const createDomain = new mutationWithClientMutationId({ // Check to see if user belongs to org const permission = await checkPermission({ orgId: org._id }) - if (!['admin', 'owner', 'super_admin'].includes(permission)) { + if (!ac.can(permission).createOwn('domain').granted) { console.warn( `User: ${userKey} attempted to create a domain in: ${org.slug}, however they do not have permission to do so.`, ) @@ -122,6 +131,17 @@ export const createDomain = new mutationWithClientMutationId({ } } + // ensure only owners can enroll or deny domains + if ( + !ac.can(permission).createOwn('cvd-enrollment').granted && + ['enrolled', 'deny'].includes(cvdEnrollment.status) + ) { + console.warn( + `User: ${userKey} attempted to update the CVD enrollment for domain: ${domain} in org: ${orgId}, however they do not have permission in that org.`, + ) + cvdEnrollment.status = cvdEnrollment.status === 'enrolled' ? 'pending' : 'not-enrolled' + } + const insertDomain = { domain: domain.toLowerCase(), lastRan: null, @@ -138,8 +158,9 @@ export const createDomain = new mutationWithClientMutationId({ spf: 'info', ssl: 'info', }, - archived: archived, + archived, ignoreRua: false, + cvdEnrollment, } // Check to see if domain already belongs to same org @@ -260,6 +281,14 @@ export const createDomain = new mutationWithClientMutationId({ }) } + if (typeof cvdEnrollment !== 'undefined') { + updatedProperties.push({ + name: 'cvdEnrollment', + oldValue: null, + newValue: cvdEnrollment.enrollment, + }) + } + await logActivity({ transaction, collections, diff --git a/api/src/domain/mutations/remove-domain.js b/api/src/domain/mutations/remove-domain.js index ecb747cb06..bde0ff54af 100644 --- a/api/src/domain/mutations/remove-domain.js +++ b/api/src/domain/mutations/remove-domain.js @@ -5,6 +5,7 @@ import { t } from '@lingui/macro' import { removeDomainUnion } from '../unions' import { logActivity } from '../../audit-logs/mutations/log-activity' import { DomainRemovalReasonEnum } from '../../enums' +import ac from '../../access-control' export const removeDomain = new mutationWithClientMutationId({ name: 'RemoveDomain', @@ -85,7 +86,7 @@ export const removeDomain = new mutationWithClientMutationId({ // Get permission const permission = await checkPermission({ orgId: org._id }) - if (['admin', 'owner', 'super_admin'].includes(permission) === false) { + if (!ac.can(permission).deleteOwn('domain').granted) { console.warn( `User: ${userKey} attempted to remove ${domain.domain} in ${org.slug} however they do not have permission in that org.`, ) @@ -98,7 +99,7 @@ export const removeDomain = new mutationWithClientMutationId({ // Check to see if domain belongs to verified check org // if domain returns NXDOMAIN, allow removal - if (org.verified && permission !== 'super_admin' && domain.rcode !== 'NXDOMAIN') { + if (org.verified && !ac.can(permission).deleteAny('domain').granted && domain.rcode !== 'NXDOMAIN') { console.warn( `User: ${userKey} attempted to remove ${domain.domain} in ${org.slug} but does not have permission to remove a domain from a verified check org.`, ) diff --git a/api/src/domain/mutations/request-scan.js b/api/src/domain/mutations/request-scan.js index 33c9389afd..c75eff28ce 100644 --- a/api/src/domain/mutations/request-scan.js +++ b/api/src/domain/mutations/request-scan.js @@ -33,7 +33,8 @@ export const requestScan = new mutationWithClientMutationId({ request: { ip }, publish, auth: { checkDomainPermission, userRequired, verifiedRequired }, - loaders: { loadDomainByDomain, loadWebConnectionsByDomainId, loadWebScansByWebId }, + loaders: { loadDomainByDomain }, + dataSources: { webScan }, validators: { cleanseInput }, }, ) => { @@ -101,7 +102,7 @@ export const requestScan = new mutationWithClientMutationId({ // Check to see if a scan is already pending try { - const webConnections = await loadWebConnectionsByDomainId({ + const webConnections = await webScan.getConnectionsByDomainId({ domainId: domain._id, limit: 1, orderBy: { field: 'timestamp', direction: 'DESC' }, @@ -109,7 +110,7 @@ export const requestScan = new mutationWithClientMutationId({ }) if (webConnections.edges.length > 0) { const webConnection = webConnections.edges[0].node - const webScans = await loadWebScansByWebId({ webId: webConnection._id }) + const webScans = await webScan.getScansByWebId({ webId: webConnection._id }) webScans.forEach((result) => { const timeDifferenceInMinutes = (Date.now() - new Date(webConnection.timestamp).getTime()) / 1000 / 60 if (result.status.toUpperCase() === 'PENDING' && timeDifferenceInMinutes < 30) { diff --git a/api/src/domain/mutations/update-domain.js b/api/src/domain/mutations/update-domain.js index 905cfae28d..a0ff59ea96 100644 --- a/api/src/domain/mutations/update-domain.js +++ b/api/src/domain/mutations/update-domain.js @@ -5,6 +5,8 @@ import { t } from '@lingui/macro' import { updateDomainUnion } from '../unions' import { logActivity } from '../../audit-logs/mutations/log-activity' import { AssetStateEnums } from '../../enums' +import { CvdEnrollmentInputOptions } from '../../additional-findings/input/cvd-enrollment-options' +import ac from '../../access-control' export const updateDomain = new mutationWithClientMutationId({ name: 'UpdateDomain', @@ -34,6 +36,11 @@ export const updateDomain = new mutationWithClientMutationId({ description: 'Value that determines how the domain relates to the organization.', type: AssetStateEnums, }, + cvdEnrollment: { + description: + 'The Coordinated Vulnerability Disclosure (CVD) enrollment details for this domain, including HackerOne integration status and CVSS requirements.', + type: CvdEnrollmentInputOptions, + }, }), outputFields: () => ({ result: { @@ -93,7 +100,14 @@ export const updateDomain = new mutationWithClientMutationId({ if (typeof args.assetState !== 'undefined') { assetState = cleanseInput(args.assetState) } else { - assetState = '' + assetState = null + } + + let cvdEnrollment + if (typeof args.cvdEnrollment !== 'undefined') { + cvdEnrollment = args.cvdEnrollment + } else { + cvdEnrollment = null } // Check to see if domain exists @@ -127,7 +141,7 @@ export const updateDomain = new mutationWithClientMutationId({ // Check permission const permission = await checkPermission({ orgId: org._id }) - if (!['admin', 'owner', 'super_admin'].includes(permission)) { + if (!ac.can(permission).updateOwn('domain').granted) { console.warn( `User: ${userKey} attempted to update domain: ${domainId} for org: ${orgId}, however they do not have permission in that org.`, ) @@ -165,6 +179,16 @@ export const updateDomain = new mutationWithClientMutationId({ } } + if ( + !ac.can(permission).updateOwn('cvd-enrollment').granted && + ['enrolled', 'deny'].includes(cvdEnrollment?.status) + ) { + console.warn( + `User: ${userKey} attempted to update the CVD enrollment for domain: ${domainId} in org: ${orgId}, however they do not have permission in that org.`, + ) + cvdEnrollment.status = cvdEnrollment.status === 'enrolled' ? 'pending' : 'not-enrolled' + } + // Setup Transaction const trx = await transaction(collections) @@ -172,6 +196,7 @@ export const updateDomain = new mutationWithClientMutationId({ const domainToInsert = { archived: typeof archived !== 'undefined' ? archived : domain?.archived, ignoreRua: typeof args.ignoreRua !== 'undefined' ? args.ignoreRua : domain?.ignoreRua, + cvdEnrollment: typeof cvdEnrollment !== 'undefined' ? cvdEnrollment : domain?.cvdEnrollment, } try { @@ -262,6 +287,14 @@ export const updateDomain = new mutationWithClientMutationId({ }) } + if (typeof cvdEnrollment !== 'undefined' && cvdEnrollment?.status !== domain?.cvdEnrollment?.status) { + updatedProperties.push({ + name: 'cvdEnrollment', + oldValue: JSON.stringify(domain.cvdEnrollment?.status), + newValue: JSON.stringify(cvdEnrollment.status), + }) + } + if (JSON.stringify(claim.tags) !== JSON.stringify(claimToInsert.tags)) { updatedProperties.push({ name: 'tags', diff --git a/api/src/domain/mutations/update-domains-by-domain-ids.js b/api/src/domain/mutations/update-domains-by-domain-ids.js index 79ad02e0aa..17d0fad6c2 100644 --- a/api/src/domain/mutations/update-domains-by-domain-ids.js +++ b/api/src/domain/mutations/update-domains-by-domain-ids.js @@ -3,6 +3,7 @@ import { bulkModifyDomainsUnion } from '../unions' import { GraphQLID, GraphQLList, GraphQLNonNull, GraphQLString } from 'graphql' import { t } from '@lingui/macro' import { logActivity } from '../../audit-logs' +import ac from '../../access-control' export const updateDomainsByDomainIds = new mutationWithClientMutationId({ name: 'UpdateDomainsByDomainIds', @@ -70,7 +71,7 @@ export const updateDomainsByDomainIds = new mutationWithClientMutationId({ // Check to see if user belongs to org const permission = await checkPermission({ orgId: org._id }) - if (!['super_admin', 'owner', 'admin'].includes(permission)) { + if (!ac.can(permission).updateOwn('domain').granted) { console.warn( `User: ${userKey} attempted to update domains in: ${org.slug}, however they do not have permission to do so.`, ) diff --git a/api/src/domain/mutations/update-domains-by-filters.js b/api/src/domain/mutations/update-domains-by-filters.js index 64919e8ee7..743d7a7950 100644 --- a/api/src/domain/mutations/update-domains-by-filters.js +++ b/api/src/domain/mutations/update-domains-by-filters.js @@ -5,6 +5,7 @@ import { t } from '@lingui/macro' import { logActivity } from '../../audit-logs' import { domainFilter } from '../inputs' import { aql } from 'arangojs' +import ac from '../../access-control' export const updateDomainsByFilters = new mutationWithClientMutationId({ name: 'UpdateDomainsByFilters', @@ -78,7 +79,7 @@ export const updateDomainsByFilters = new mutationWithClientMutationId({ // Check to see if user belongs to org const permission = await checkPermission({ orgId: org._id }) - if (!['super_admin', 'owner', 'admin'].includes(permission)) { + if (!ac.can(permission).updateOwn('domain').granted) { console.warn( `User: ${userKey} attempted to update domains in: ${org.slug}, however they do not have permission to do so.`, ) diff --git a/api/src/domain/objects/__tests__/domain.test.js b/api/src/domain/objects/__tests__/domain.test.js index 6d32aadf21..b36bc258dd 100644 --- a/api/src/domain/objects/__tests__/domain.test.js +++ b/api/src/domain/objects/__tests__/domain.test.js @@ -88,6 +88,10 @@ describe('given the domain object', () => { expect(demoType).toHaveProperty('yearlyDmarcSummaries') expect(demoType.yearlyDmarcSummaries.type).toMatchObject(new GraphQLList(dmarcSummaryType)) }) + it('has a cvdEnrollment field', () => { + const demoType = domainType.getFields() + expect(demoType).toHaveProperty('cvdEnrollment') + }) }) describe('testing the field resolvers', () => { const consoleOutput = [] @@ -100,6 +104,37 @@ describe('given the domain object', () => { consoleOutput.length = 0 }) + describe('testing the cvdEnrollment resolver', () => { + it('returns the resolved value with correct structure when user is authenticated', async () => { + const demoType = domainType.getFields() + const mockUserRequired = jest.fn() + const cvdEnrollmentValue = { + status: 'ENROLLED', + description: 'Test asset', + maxSeverity: 'HIGH', + confidentialityRequirement: 'HIGH', + integrityRequirement: 'LOW', + availabilityRequirement: 'LOW', + } + + await expect( + demoType.cvdEnrollment.resolve( + { cvdEnrollment: cvdEnrollmentValue }, + {}, + { auth: { userRequired: mockUserRequired } }, + ), + ).resolves.toEqual(cvdEnrollmentValue) + expect(mockUserRequired).toHaveBeenCalled() + }) + it('returns undefined if cvdEnrollment is not present', async () => { + const demoType = domainType.getFields() + const mockUserRequired = jest.fn() + await expect( + demoType.cvdEnrollment.resolve({}, {}, { auth: { userRequired: mockUserRequired } }), + ).resolves.toBeUndefined() + }) + }) + describe('testing the id resolver', () => { it('returns the resolved value', () => { const demoType = domainType.getFields() @@ -180,12 +215,14 @@ describe('given the domain object', () => { expect( demoType.selectors.resolve( - { selectors }, + { _id: 'domains/1', selectors }, {}, { auth: { userRequired: jest.fn().mockReturnValue(true), - checkDomainPermission: jest.fn().mockReturnValue(true), + }, + dataSources: { + auth: { domainPermissionByDomainId: { load: jest.fn().mockResolvedValue(true) } }, }, loaders: { loadDkimSelectorsByDomainId: jest.fn().mockReturnValue(selectors), @@ -269,8 +306,10 @@ describe('given the domain object', () => { { _id: '1' }, { first: 1 }, { - loaders: { - loadOrgConnectionsByDomainId: jest.fn().mockReturnValue(expectedResult), + dataSources: { + organization: { + connectionsByDomainId: jest.fn().mockReturnValue(expectedResult), + }, }, auth: { checkSuperAdmin: jest.fn().mockReturnValue(false), @@ -288,12 +327,11 @@ describe('given the domain object', () => { { _id: '1' }, { limit: 1 }, { - loaders: { - loadWebConnectionsByDomainId: jest.fn().mockReturnValue({ _id: '1', _key: '1' }), + dataSources: { + auth: { domainPermissionByDomainId: { load: jest.fn().mockResolvedValue(true) } }, + webScan: { getConnectionsByDomainId: jest.fn().mockReturnValue({ _id: '1', _key: '1' }) }, }, auth: { - checkDomainPermission: jest.fn().mockReturnValue(true), - checkSuperAdmin: jest.fn().mockReturnValue(false), userRequired: jest.fn().mockReturnValue(true), }, }, @@ -313,12 +351,11 @@ describe('given the domain object', () => { { _id: '1' }, { limit: 1 }, { - loaders: { - loadDnsConnectionsByDomainId: jest.fn().mockReturnValue({ _id: '1', _key: '1' }), + dataSources: { + auth: { domainPermissionByDomainId: { load: jest.fn().mockResolvedValue(true) } }, + dnsScan: { getConnectionsByDomainId: jest.fn().mockReturnValue({ _id: '1', _key: '1' }) }, }, auth: { - checkDomainPermission: jest.fn().mockReturnValue(true), - checkSuperAdmin: jest.fn().mockReturnValue(false), userRequired: jest.fn().mockReturnValue(true), }, }, diff --git a/api/src/domain/objects/domain.js b/api/src/domain/objects/domain.js index b32c24700f..21956c7543 100644 --- a/api/src/domain/objects/domain.js +++ b/api/src/domain/objects/domain.js @@ -14,9 +14,9 @@ import { organizationConnection } from '../../organization/objects' import { GraphQLDateTime } from 'graphql-scalars' import { dnsOrder } from '../../dns-scan/inputs' import { webOrder } from '../../web-scan/inputs/web-order' -import { mxRecordConnection } from '../../dns-scan/objects/mx-record-connection' import { additionalFinding } from '../../additional-findings/objects/additional-finding' import { tagType } from '../../tags/objects' +import { cvdEnrollment } from '../../additional-findings/objects' export const domainType = new GraphQLObjectType({ name: 'Domain', @@ -56,10 +56,10 @@ export const domainType = new GraphQLObjectType({ resolve: async ( { _id }, _, - { userKey, auth: { checkDomainPermission, userRequired }, loaders: { loadDkimSelectorsByDomainId } }, + { userKey, auth: { userRequired }, dataSources: { auth: authDS }, loaders: { loadDkimSelectorsByDomainId } }, ) => { await userRequired() - const permitted = await checkDomainPermission({ domainId: _id }) + const permitted = await authDS.domainPermissionByDomainId.load(_id) if (!permitted) { console.warn(`User: ${userKey} attempted to access selectors for ${_id}, but does not have permission.`) throw new Error(t`Cannot query domain selectors without permission.`) @@ -122,10 +122,10 @@ export const domainType = new GraphQLObjectType({ ...connectionArgs, }, description: 'The organization that this domain belongs to.', - resolve: async ({ _id }, args, { auth: { checkSuperAdmin }, loaders: { loadOrgConnectionsByDomainId } }) => { + resolve: async ({ _id }, args, { auth: { checkSuperAdmin }, dataSources: { organization } }) => { const isSuperAdmin = await checkSuperAdmin() - return await loadOrgConnectionsByDomainId({ + return await organization.connectionsByDomainId({ domainId: _id, isSuperAdmin, ...args, @@ -154,13 +154,9 @@ export const domainType = new GraphQLObjectType({ ...connectionArgs, }, description: `DNS scan results.`, - resolve: async ( - { _id }, - args, - { userKey, auth: { checkDomainPermission, userRequired }, loaders: { loadDnsConnectionsByDomainId } }, - ) => { + resolve: async ({ _id }, args, { userKey, auth: { userRequired }, dataSources: { auth: authDS, dnsScan } }) => { await userRequired() - const permitted = await checkDomainPermission({ domainId: _id }) + const permitted = await authDS.domainPermissionByDomainId.load(_id) if (!permitted) { console.warn( `User: ${userKey} attempted to access dns scan results for ${_id}, but does not have permission.`, @@ -168,49 +164,7 @@ export const domainType = new GraphQLObjectType({ throw new Error(t`Cannot query dns scan results without permission.`) } - return await loadDnsConnectionsByDomainId({ - domainId: _id, - ...args, - }) - }, - }, - mxRecordDiff: { - type: mxRecordConnection.connectionType, - description: 'List of MX record diffs for a given domain.', - args: { - startDate: { - type: GraphQLDateTime, - description: 'Start date for date filter.', - }, - endDate: { - type: GraphQLDateTime, - description: 'End date for date filter.', - }, - orderBy: { - type: dnsOrder, - description: 'Ordering options for MX connections.', - }, - limit: { - type: GraphQLInt, - description: 'Number of MX scans to retrieve.', - }, - ...connectionArgs, - }, - resolve: async ( - { _id }, - args, - { userKey, auth: { checkDomainPermission, userRequired }, loaders: { loadMxRecordDiffByDomainId } }, - ) => { - await userRequired() - const permitted = await checkDomainPermission({ domainId: _id }) - if (!permitted) { - console.warn( - `User: ${userKey} attempted to access web scan results for ${_id}, but does not have permission.`, - ) - throw new Error(t`Cannot query web scan results without permission.`) - } - - return await loadMxRecordDiffByDomainId({ + return await dnsScan.getConnectionsByDomainId({ domainId: _id, ...args, }) @@ -242,13 +196,9 @@ export const domainType = new GraphQLObjectType({ }, ...connectionArgs, }, - resolve: async ( - { _id }, - args, - { userKey, auth: { checkDomainPermission, userRequired }, loaders: { loadWebConnectionsByDomainId } }, - ) => { + resolve: async ({ _id }, args, { userKey, auth: { userRequired }, dataSources: { auth: authDS, webScan } }) => { await userRequired() - const permitted = await checkDomainPermission({ domainId: _id }) + const permitted = await authDS.domainPermissionByDomainId.load(_id) if (!permitted) { console.warn( `User: ${userKey} attempted to access web scan results for ${_id}, but does not have permission.`, @@ -256,7 +206,7 @@ export const domainType = new GraphQLObjectType({ throw new Error(t`Cannot query web scan results without permission.`) } - return await loadWebConnectionsByDomainId({ + return await webScan.getConnectionsByDomainId({ domainId: _id, ...args, }) @@ -268,10 +218,10 @@ export const domainType = new GraphQLObjectType({ resolve: async ( { _id }, _, - { userKey, auth: { checkDomainPermission, userRequired }, loaders: { loadAdditionalFindingsByDomainId } }, + { userKey, auth: { userRequired }, dataSources: { auth: authDS, additionalFindings } }, ) => { await userRequired() - const permitted = await checkDomainPermission({ domainId: _id }) + const permitted = await authDS.domainPermissionByDomainId.load(_id) if (!permitted) { console.warn( `User: ${userKey} attempted to access additional findings for domain: ${_id}, but does not have permission.`, @@ -279,7 +229,7 @@ export const domainType = new GraphQLObjectType({ throw new Error(t`Cannot query additional findings without permission.`) } - return await loadAdditionalFindingsByDomainId({ + return await additionalFindings.getByDomainId({ domainId: _id, }) }, @@ -334,7 +284,7 @@ export const domainType = new GraphQLObjectType({ return { domainKey: _key, _id: dmarcSummaryEdge._to, - startDate: startDate, + startDate, } }, }, @@ -391,10 +341,8 @@ export const domainType = new GraphQLObjectType({ description: 'Value that determines if a user is affiliated with a domain, whether through organization affiliation, verified organization network affiliation, or through super admin status.', type: GraphQLBoolean, - resolve: async ({ _id }, __, { auth: { checkDomainPermission } }) => { - return await checkDomainPermission({ - domainId: _id, - }) + resolve: async ({ _id }, __, { dataSources: { auth: authDS } }) => { + return await authDS.domainPermissionByDomainId.load(_id) }, }, ignoreRua: { @@ -417,6 +365,16 @@ export const domainType = new GraphQLObjectType({ description: `Whether or not a CVE has been detected in the domain's additional findings.`, resolve: ({ cveDetected }) => cveDetected, }, + cvdEnrollment: { + type: cvdEnrollment, + description: + 'The Coordinated Vulnerability Disclosure (CVD) enrollment status and requirements for this domain asset, including HackerOne integration details.', + resolve: async ({ cvdEnrollment }, __, { auth: { userRequired } }) => { + await userRequired() + + return cvdEnrollment + }, + }, }), interfaces: [nodeInterface], description: 'Domain object containing information for a given domain.', diff --git a/api/src/domain/queries/__tests__/find-domain-by-domain.test.js b/api/src/domain/queries/__tests__/find-domain-by-domain.test.js index 40559ea2f9..dea6da436b 100644 --- a/api/src/domain/queries/__tests__/find-domain-by-domain.test.js +++ b/api/src/domain/queries/__tests__/find-domain-by-domain.test.js @@ -9,7 +9,7 @@ import frenchMessages from '../../../locale/fr/messages' import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' -import { checkDomainPermission, userRequired, verifiedRequired } from '../../../auth' +import { checkDomainPermission, userRequired, verifiedRequired, AuthDataSource } from '../../../auth' import { loadDkimSelectorsByDomainId, loadDomainByDomain } from '../../loaders' import { loadUserByKey } from '../../../user/loaders' import dbschema from '../../../../database.json' @@ -142,7 +142,7 @@ describe('given findDomainByDomain query', () => { contextValue: { i18n, userKey: user._key, - query: query, + query, auth: { loginRequiredBool: true, checkDomainPermission: checkDomainPermission({ @@ -155,6 +155,9 @@ describe('given findDomainByDomain query', () => { }), verifiedRequired: verifiedRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + }, validators: { cleanseInput, }, @@ -236,7 +239,7 @@ describe('given findDomainByDomain query', () => { contextValue: { i18n, userKey: 1, - query: query, + query, auth: { checkDomainPermission: jest.fn().mockReturnValue(true), userRequired: jest.fn().mockReturnValue({ @@ -351,7 +354,7 @@ describe('given findDomainByDomain query', () => { contextValue: { i18n, userKey: 1, - query: query, + query, auth: { checkDomainPermission: jest.fn().mockReturnValue(true), userRequired: jest.fn().mockReturnValue({ diff --git a/api/src/domain/queries/__tests__/find-my-domains.test.js b/api/src/domain/queries/__tests__/find-my-domains.test.js index 9efcba4fac..db218facd9 100644 --- a/api/src/domain/queries/__tests__/find-my-domains.test.js +++ b/api/src/domain/queries/__tests__/find-my-domains.test.js @@ -9,7 +9,7 @@ import frenchMessages from '../../../locale/fr/messages' import { createQuerySchema } from '../../../query' import { createMutationSchema } from '../../../mutation' import { cleanseInput } from '../../../validators' -import { checkDomainPermission, checkSuperAdmin, userRequired, verifiedRequired } from '../../../auth' +import { AuthDataSource, checkDomainPermission, checkSuperAdmin, userRequired, verifiedRequired } from '../../../auth' import { loadDkimSelectorsByDomainId, loadDomainConnectionsByUserId } from '../../loaders' import { loadUserByKey } from '../../../user' import dbschema from '../../../../database.json' @@ -195,6 +195,9 @@ describe('given findMyDomainsQuery', () => { }), verifiedRequired: verifiedRequired({}), }, + dataSources: { + auth: new AuthDataSource({ query, userKey: user._key }), + }, loaders: { loadDomainConnectionsByUserId: loadDomainConnectionsByUserId({ query, diff --git a/api/src/enums/cvd-requirement.js b/api/src/enums/cvd-requirement.js new file mode 100644 index 0000000000..d37aa1b9c0 --- /dev/null +++ b/api/src/enums/cvd-requirement.js @@ -0,0 +1,20 @@ +import { GraphQLEnumType } from 'graphql' + +export const CvdRequirementEnums = new GraphQLEnumType({ + name: 'CvdRequirementEnums', + values: { + NONE: { + value: 'none', + description: 'No additional CVSS environmental requirement for this asset.', + }, + LOW: { + value: 'low', + description: 'Low CVSS environmental requirement for this asset.', + }, + HIGH: { + value: 'high', + description: 'High CVSS environmental requirement for this asset.', + }, + }, + description: 'Enumerates the CVSS environmental requirement levels for CVD-enrolled assets.', +}) diff --git a/api/src/enums/domain-tag-label.js b/api/src/enums/domain-tag-label.js index 1e9f61599c..6ae43ca99f 100644 --- a/api/src/enums/domain-tag-label.js +++ b/api/src/enums/domain-tag-label.js @@ -31,6 +31,19 @@ export const DomainTagLabel = new GraphQLEnumType({ value: 'cve-detected', description: 'Label for tagging domains that have vulnerabilities.', }, + CVD_ENROLLED: { + value: 'cvd-enrolled', + description: 'Label for tagging domains that are enrolled in the Coordinated Vulnerability Disclosure program.', + }, + CVD_PENDING: { + value: 'cvd-pending', + description: + 'Label for tagging domains that are pending enrollment in the Coordinated Vulnerability Disclosure program.', + }, + CVD_DENY: { + value: 'cvd-deny', + description: 'Label for tagging domains that have been explicitly excluded from the Coordinated Vulnerability Disclosure program.', + }, }, description: 'An enum used to assign and test user-generated domain tags', }) diff --git a/api/src/enums/enrollment-status.js b/api/src/enums/enrollment-status.js new file mode 100644 index 0000000000..1ab1c2a334 --- /dev/null +++ b/api/src/enums/enrollment-status.js @@ -0,0 +1,24 @@ +import { GraphQLEnumType } from 'graphql' + +export const EnrollmentStatusEnums = new GraphQLEnumType({ + name: 'EnrollmentStatusEnums', + values: { + ENROLLED: { + value: 'enrolled', + description: 'The asset is enrolled in the CVD program and eligible for coordinated vulnerability disclosure.', + }, + PENDING: { + value: 'pending', + description: 'The asset enrollment is pending approval for the CVD program.', + }, + NOT_ENROLLED: { + value: 'not-enrolled', + description: 'The asset is not enrolled in the CVD program.', + }, + DENY: { + value: 'deny', + description: 'The asset has been explicitly excluded from the CVD program.', + }, + }, + description: 'Enumerates the possible enrollment states for the Coordinated Vulnerability Disclosure (CVD) program.', +}) diff --git a/api/src/enums/index.js b/api/src/enums/index.js index 67f3eadd17..3cf345b67e 100644 --- a/api/src/enums/index.js +++ b/api/src/enums/index.js @@ -33,3 +33,5 @@ export * from './tag-ownership' export * from './system-filter-value' export * from './domain-filter-category' export * from './dmarc-phase' +export * from './enrollment-status' +export * from './cvd-requirement' diff --git a/api/src/guidance-tag/data-source.js b/api/src/guidance-tag/data-source.js new file mode 100644 index 0000000000..913b78e361 --- /dev/null +++ b/api/src/guidance-tag/data-source.js @@ -0,0 +1,35 @@ +import { + loadAggregateGuidanceTagByTagId, + loadAggregateGuidanceTagConnectionsByTagId, + loadDkimGuidanceTagByTagId, + loadDkimGuidanceTagConnectionsByTagId, + loadDmarcGuidanceTagByTagId, + loadDmarcGuidanceTagConnectionsByTagId, + loadGuidanceTagByTagId, + loadGuidanceTagSummaryConnectionsByTagId, + loadHttpsGuidanceTagByTagId, + loadHttpsGuidanceTagConnectionsByTagId, + loadSpfGuidanceTagByTagId, + loadSpfGuidanceTagConnectionsByTagId, + loadSslGuidanceTagByTagId, + loadSslGuidanceTagConnectionsByTagId, +} from './loaders' + +export class GuidanceTagDataSource { + constructor({ query, userKey, i18n, language, cleanseInput }) { + this.byTagId = loadGuidanceTagByTagId({ query, userKey, i18n, language }) + this.summaryConnectionsByTagId = loadGuidanceTagSummaryConnectionsByTagId({ query, userKey, cleanseInput, i18n, language }) + this.aggregateByTagId = loadAggregateGuidanceTagByTagId({ query, userKey, i18n, language }) + this.aggregateConnectionsByTagId = loadAggregateGuidanceTagConnectionsByTagId({ query, userKey, cleanseInput, i18n, language }) + this.dkimByTagId = loadDkimGuidanceTagByTagId({ query, userKey, i18n, language }) + this.dkimConnectionsByTagId = loadDkimGuidanceTagConnectionsByTagId({ query, userKey, cleanseInput, i18n, language }) + this.dmarcByTagId = loadDmarcGuidanceTagByTagId({ query, userKey, i18n, language }) + this.dmarcConnectionsByTagId = loadDmarcGuidanceTagConnectionsByTagId({ query, userKey, cleanseInput, i18n, language }) + this.httpsByTagId = loadHttpsGuidanceTagByTagId({ query, userKey, i18n, language }) + this.httpsConnectionsByTagId = loadHttpsGuidanceTagConnectionsByTagId({ query, userKey, cleanseInput, i18n, language }) + this.spfByTagId = loadSpfGuidanceTagByTagId({ query, userKey, i18n, language }) + this.spfConnectionsByTagId = loadSpfGuidanceTagConnectionsByTagId({ query, userKey, cleanseInput, i18n, language }) + this.sslByTagId = loadSslGuidanceTagByTagId({ query, userKey, i18n, language }) + this.sslConnectionsByTagId = loadSslGuidanceTagConnectionsByTagId({ query, userKey, cleanseInput, i18n, language }) + } +} diff --git a/api/src/guidance-tag/index.js b/api/src/guidance-tag/index.js index 6d2a5b5879..52de3be3af 100644 --- a/api/src/guidance-tag/index.js +++ b/api/src/guidance-tag/index.js @@ -1,3 +1,4 @@ +export * from './data-source' export * from './inputs' export * from './loaders' export * from './objects' diff --git a/api/src/initialize-loaders.js b/api/src/initialize-loaders.js index a50134dd5e..1ab26ba52e 100644 --- a/api/src/initialize-loaders.js +++ b/api/src/initialize-loaders.js @@ -1,10 +1,8 @@ -import { loadAdditionalFindingsByDomainId, loadTop25Reports } from './additional-findings/loaders' import { loadAffiliationByKey, loadAffiliationConnectionsByUserId, loadAffiliationConnectionsByOrgId, } from './affiliation/loaders' -import { loadAuditLogsByOrgId } from './audit-logs/loaders' import { loadDkimFailConnectionsBySumId, loadDmarcFailConnectionsBySumId, @@ -24,33 +22,8 @@ import { loadDomainConnectionsByUserId, loadDkimSelectorsByDomainId, } from './domain/loaders' -import { - loadAggregateGuidanceTagByTagId, - loadAggregateGuidanceTagConnectionsByTagId, - loadDkimGuidanceTagByTagId, - loadDkimGuidanceTagConnectionsByTagId, - loadDmarcGuidanceTagByTagId, - loadDmarcGuidanceTagConnectionsByTagId, - loadHttpsGuidanceTagByTagId, - loadHttpsGuidanceTagConnectionsByTagId, - loadSpfGuidanceTagByTagId, - loadSpfGuidanceTagConnectionsByTagId, - loadSslGuidanceTagByTagId, - loadSslGuidanceTagConnectionsByTagId, - loadGuidanceTagByTagId, - loadGuidanceTagSummaryConnectionsByTagId, -} from './guidance-tag/loaders' -import { - loadOrgByKey, - loadOrgBySlug, - loadOrgConnectionsByDomainId, - loadOrgConnectionsByUserId, - loadAllOrganizationDomainStatuses, - loadOrganizationDomainStatuses, - loadOrganizationSummariesByPeriod, -} from './organization/loaders' +import { loadOrgByKey, loadOrganizationNamesById } from './organization/loaders' import { loadMyTrackerByUserId, loadUserByUserName, loadUserByKey, loadUserConnectionsByUserId } from './user/loaders' -import { loadWebConnectionsByDomainId, loadWebScansByWebId } from './web-scan/loaders' import { loadVerifiedDomainsById, loadVerifiedDomainByKey, @@ -63,23 +36,10 @@ import { loadVerifiedOrgConnectionsByDomainId, loadVerifiedOrgConnections, } from './verified-organizations/loaders' -import { loadChartSummaryByKey, loadChartSummariesByPeriod } from './summaries/loaders' -import { loadDnsConnectionsByDomainId, loadMxRecordDiffByDomainId } from './dns-scan' -import { loadAllTags, loadTagByTagId, loadTagsByOrg } from './tags' +import { loadTagByTagId, loadTagsByOrg } from './tags' -export function initializeLoaders({ query, db, userKey, i18n, language, cleanseInput, loginRequiredBool, moment }) { +export function initializeLoaders({ query, userKey, i18n, language, cleanseInput, loginRequiredBool, moment }) { return { - loadAdditionalFindingsByDomainId: loadAdditionalFindingsByDomainId({ - query, - userKey, - i18n, - }), - loadAllTags: loadAllTags({ - query, - userKey, - i18n, - language, - }), loadTagByTagId: loadTagByTagId({ query, userKey, @@ -92,38 +52,6 @@ export function initializeLoaders({ query, db, userKey, i18n, language, cleanseI i18n, language, }), - loadTop25Reports: loadTop25Reports({ - query, - userKey, - i18n, - language, - }), - loadChartSummaryByKey: loadChartSummaryByKey({ query, userKey, i18n }), - loadChartSummariesByPeriod: loadChartSummariesByPeriod({ - query, - userKey, - cleanseInput, - i18n, - }), - loadAggregateGuidanceTagByTagId: loadAggregateGuidanceTagByTagId({ - query, - userKey, - i18n, - language, - }), - loadAggregateGuidanceTagConnectionsByTagId: loadAggregateGuidanceTagConnectionsByTagId({ - query, - userKey, - i18n, - cleanseInput, - language, - }), - loadAuditLogsByOrgId: loadAuditLogsByOrgId({ - query, - userKey, - i18n, - cleanseInput, - }), loadDkimFailConnectionsBySumId: loadDkimFailConnectionsBySumId({ query, userKey, @@ -196,163 +124,8 @@ export function initializeLoaders({ query, db, userKey, i18n, language, cleanseI i18n, auth: { loginRequiredBool }, }), - loadDnsConnectionsByDomainId: loadDnsConnectionsByDomainId({ - query, - db, - userKey, - cleanseInput, - i18n, - }), - loadMxRecordDiffByDomainId: loadMxRecordDiffByDomainId({ - query, - db, - userKey, - cleanseInput, - i18n, - }), - loadWebConnectionsByDomainId: loadWebConnectionsByDomainId({ - query, - db, - userKey, - cleanseInput, - i18n, - }), - loadWebScansByWebId: loadWebScansByWebId({ - query, - db, - userKey, - cleanseInput, - i18n, - }), - loadDkimGuidanceTagByTagId: loadDkimGuidanceTagByTagId({ - query, - userKey, - i18n, - language, - }), - loadDkimGuidanceTagConnectionsByTagId: loadDkimGuidanceTagConnectionsByTagId({ - query, - userKey, - cleanseInput, - i18n, - language, - }), - loadDmarcGuidanceTagByTagId: loadDmarcGuidanceTagByTagId({ - query, - userKey, - i18n, - language, - }), - loadDmarcGuidanceTagConnectionsByTagId: loadDmarcGuidanceTagConnectionsByTagId({ - query, - userKey, - cleanseInput, - i18n, - language, - }), - loadGuidanceTagSummaryConnectionsByTagId: loadGuidanceTagSummaryConnectionsByTagId({ - query, - userKey, - cleanseInput, - i18n, - language, - }), - loadGuidanceTagByTagId: loadGuidanceTagByTagId({ - query, - userKey, - i18n, - language, - }), - loadHttpsGuidanceTagByTagId: loadHttpsGuidanceTagByTagId({ - query, - userKey, - i18n, - language, - }), - loadHttpsGuidanceTagConnectionsByTagId: loadHttpsGuidanceTagConnectionsByTagId({ - query, - userKey, - cleanseInput, - i18n, - language, - }), - loadSpfGuidanceTagByTagId: loadSpfGuidanceTagByTagId({ - query, - userKey, - i18n, - language, - }), - loadSpfGuidanceTagConnectionsByTagId: loadSpfGuidanceTagConnectionsByTagId({ - query, - userKey, - cleanseInput, - i18n, - language, - }), - loadSslGuidanceTagByTagId: loadSslGuidanceTagByTagId({ - query, - userKey, - i18n, - language, - }), - loadSslGuidanceTagConnectionsByTagId: loadSslGuidanceTagConnectionsByTagId({ - query, - userKey, - cleanseInput, - i18n, - language, - }), - loadOrgByKey: loadOrgByKey({ - query, - language, - userKey, - i18n, - }), - loadOrgBySlug: loadOrgBySlug({ - query, - language, - userKey, - i18n, - }), - loadOrgConnectionsByDomainId: loadOrgConnectionsByDomainId({ - query, - language, - userKey, - cleanseInput, - i18n, - auth: { loginRequiredBool }, - }), - loadOrgConnectionsByUserId: loadOrgConnectionsByUserId({ - query, - userKey, - cleanseInput, - language, - i18n, - auth: { loginRequiredBool }, - }), - loadOrganizationSummariesByPeriod: loadOrganizationSummariesByPeriod({ - query, - userKey, - cleanseInput, - language, - i18n, - auth: { loginRequiredBool }, - }), - loadAllOrganizationDomainStatuses: loadAllOrganizationDomainStatuses({ - query, - userKey, - cleanseInput, - language, - i18n, - }), - loadOrganizationDomainStatuses: loadOrganizationDomainStatuses({ - query, - userKey, - cleanseInput, - language, - i18n, - auth: { loginRequiredBool }, - }), + loadOrgByKey: loadOrgByKey({ query, language, userKey, i18n }), + loadOrganizationNamesById: loadOrganizationNamesById({ query, userKey, i18n }), loadMyTrackerByUserId: loadMyTrackerByUserId({ query, language, diff --git a/api/src/locale/en/messages.po b/api/src/locale/en/messages.po index 3a7487908d..554afd988e 100644 --- a/api/src/locale/en/messages.po +++ b/api/src/locale/en/messages.po @@ -19,8 +19,8 @@ msgstr "" #: src/dmarc-summaries/loaders/load-dmarc-sum-connections-by-user-id.js:202 #: src/dmarc-summaries/loaders/load-full-pass-connections-by-sum-id.js:83 #: src/dmarc-summaries/loaders/load-spf-failure-connections-by-sum-id.js:83 -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:177 -#: src/domain/loaders/load-domain-connections-by-user-id.js:204 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:178 +#: src/domain/loaders/load-domain-connections-by-user-id.js:205 #: src/guidance-tag/loaders/load-aggregate-guidance-tags-connections.js:132 #: src/guidance-tag/loaders/load-dkim-guidance-tags-connections.js:136 #: src/guidance-tag/loaders/load-dmarc-guidance-tags-connections.js:136 @@ -66,8 +66,8 @@ msgstr "`{argSet}` on the `DmarcFailureTable` connection cannot be less than zer msgid "`{argSet}` on the `DmarcSummaries` connection cannot be less than zero." msgstr "`{argSet}` on the `DmarcSummaries` connection cannot be less than zero." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:156 -#: src/domain/loaders/load-domain-connections-by-user-id.js:181 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:157 +#: src/domain/loaders/load-domain-connections-by-user-id.js:182 msgid "`{argSet}` on the `Domain` connection cannot be less than zero." msgstr "`{argSet}` on the `Domain` connection cannot be less than zero." @@ -123,33 +123,35 @@ msgstr "`{argSet}` on the `VerifiedDomain` connection cannot be less than zero." msgid "`{argSet}` on the `VerifiedOrganization` connection cannot be less than zero." msgstr "`{argSet}` on the `VerifiedOrganization` connection cannot be less than zero." -#: src/organization/objects/organization.js:244 +#: src/organization/objects/organization.js:240 #: src/organization/queries/get-all-organization-domain-statuses.js:69 msgid "Assess" msgstr "Assess" -#: src/auth/check-permission.js:18 -#: src/auth/check-permission.js:57 -#: src/auth/user-required.js:10 -#: src/auth/user-required.js:21 -#: src/auth/user-required.js:28 +#: src/auth/checks/check-permission.js:18 +#: src/auth/checks/check-permission.js:57 +#: src/auth/guards/user-required.js:10 +#: src/auth/guards/user-required.js:21 +#: src/auth/guards/user-required.js:28 +#: src/auth/loaders/load-permission-by-org-id.js:19 +#: src/auth/loaders/load-permission-by-org-id.js:63 msgid "Authentication error. Please sign in." msgstr "Authentication error. Please sign in." -#: src/domain/objects/domain.js:279 +#: src/domain/objects/domain.js:229 msgid "Cannot query additional findings without permission." msgstr "Cannot query additional findings without permission." -#: src/organization/objects/organization.js:378 +#: src/organization/objects/organization.js:359 msgid "Cannot query affiliations on organization without admin permission or higher." msgstr "Cannot query affiliations on organization without admin permission or higher." #: src/audit-logs/loaders/load-audit-logs-by-org-id.js:224 -#: src/audit-logs/queries/find-audit-logs.js:51 +#: src/audit-logs/queries/find-audit-logs.js:53 msgid "Cannot query audit logs on organization without admin permission or higher." msgstr "Cannot query audit logs on organization without admin permission or higher." -#: src/domain/objects/domain.js:168 +#: src/domain/objects/domain.js:164 msgid "Cannot query dns scan results without permission." msgstr "Cannot query dns scan results without permission." @@ -157,8 +159,7 @@ msgstr "Cannot query dns scan results without permission." msgid "Cannot query domain selectors without permission." msgstr "Cannot query domain selectors without permission." -#: src/domain/objects/domain.js:210 -#: src/domain/objects/domain.js:256 +#: src/domain/objects/domain.js:206 msgid "Cannot query web scan results without permission." msgstr "Cannot query web scan results without permission." @@ -170,7 +171,7 @@ msgstr "CVE is already ignored for this domain." msgid "CVE is not ignored for this domain." msgstr "CVE is not ignored for this domain." -#: src/organization/objects/organization.js:246 +#: src/organization/objects/organization.js:242 #: src/organization/queries/get-all-organization-domain-statuses.js:71 msgid "Deploy" msgstr "Deploy" @@ -179,13 +180,13 @@ msgstr "Deploy" msgid "Email already in use." msgstr "Email already in use." -#: src/organization/objects/organization.js:248 +#: src/organization/objects/organization.js:244 #: src/organization/queries/get-all-organization-domain-statuses.js:73 msgid "Enforce" msgstr "Enforce" -#: src/domain/mutations/request-scan.js:89 -#: src/domain/mutations/request-scan.js:99 +#: src/domain/mutations/request-scan.js:90 +#: src/domain/mutations/request-scan.js:100 msgid "Error while requesting scan. Please try again." msgstr "Error while requesting scan. Please try again." @@ -212,11 +213,11 @@ msgstr "Incorrect token value. Please request a new email." msgid "Incorrect username or password. Please try again." msgstr "Incorrect username or password. Please try again." -#: src/auth/verify-jwt.js:15 +#: src/auth/utils/verify-jwt.js:15 msgid "Invalid token, please sign in." msgstr "Invalid token, please sign in." -#: src/organization/objects/organization.js:250 +#: src/organization/objects/organization.js:246 #: src/organization/queries/get-all-organization-domain-statuses.js:75 msgid "Maintain" msgstr "Maintain" @@ -229,7 +230,7 @@ msgstr "Message dismissed successfully" msgid "New passwords do not match." msgstr "New passwords do not match." -#: src/organization/queries/find-organization-by-slug.js:41 +#: src/organization/queries/find-organization-by-slug.js:42 #: src/user/queries/find-my-tracker.js:29 msgid "No organization with the provided slug could be found." msgstr "No organization with the provided slug could be found." @@ -242,22 +243,22 @@ msgstr "No verified domain with the provided domain could be found." msgid "No verified organization with the provided slug could be found." msgstr "No verified organization with the provided slug could be found." -#: src/organization/mutations/verify-organization.js:81 +#: src/organization/mutations/verify-organization.js:78 msgid "Organization has already been verified." msgstr "Organization has already been verified." -#: src/organization/mutations/update-organization.js:184 +#: src/organization/mutations/update-organization.js:167 msgid "Organization name already in use, please choose another and try again." msgstr "Organization name already in use, please choose another and try again." -#: src/organization/mutations/create-organization.js:125 +#: src/organization/mutations/create-organization.js:85 msgid "Organization name already in use. Please try again with a different name." msgstr "Organization name already in use. Please try again with a different name." -#: src/auth/check-domain-ownership.js:29 -#: src/auth/check-domain-ownership.js:39 -#: src/auth/check-domain-ownership.js:65 -#: src/auth/check-domain-ownership.js:74 +#: src/auth/checks/check-domain-ownership.js:29 +#: src/auth/checks/check-domain-ownership.js:39 +#: src/auth/checks/check-domain-ownership.js:65 +#: src/auth/checks/check-domain-ownership.js:74 msgid "Ownership check error. Unable to request domain information." msgstr "Ownership check error. Unable to request domain information." @@ -291,8 +292,8 @@ msgstr "Passing both `first` and `last` to paginate the `DmarcFailureTable` conn msgid "Passing both `first` and `last` to paginate the `DmarcSummaries` connection is not supported." msgstr "Passing both `first` and `last` to paginate the `DmarcSummaries` connection is not supported." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:147 -#: src/domain/loaders/load-domain-connections-by-user-id.js:172 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:148 +#: src/domain/loaders/load-domain-connections-by-user-id.js:173 msgid "Passing both `first` and `last` to paginate the `Domain` connection is not supported." msgstr "Passing both `first` and `last` to paginate the `Domain` connection is not supported." @@ -365,14 +366,17 @@ msgstr "Password was successfully updated." msgid "Passwords do not match." msgstr "Passwords do not match." -#: src/auth/check-domain-permission.js:22 -#: src/auth/check-domain-permission.js:51 -#: src/auth/check-domain-permission.js:61 +#: src/auth/checks/check-domain-permission.js:22 +#: src/auth/checks/check-domain-permission.js:51 +#: src/auth/checks/check-domain-permission.js:61 +#: src/auth/loaders/load-domain-permission-by-domain-id.js:19 +#: src/auth/loaders/load-domain-permission-by-domain-id.js:51 +#: src/auth/loaders/load-domain-permission-by-domain-id.js:61 msgid "Permission check error. Unable to request domain information." msgstr "Permission check error. Unable to request domain information." #: src/organization/queries/find-organization-by-slug.js:50 -#: src/organization/queries/find-organization-by-slug.js:55 +#: src/organization/queries/find-organization-by-slug.js:52 msgid "Permission Denied: Could not retrieve specified organization." msgstr "Permission Denied: Could not retrieve specified organization." @@ -388,11 +392,11 @@ msgstr "Permission Denied: Please contact org owner to transfer ownership." msgid "Permission Denied: Please contact organization admin for help with archiving domains." msgstr "Permission Denied: Please contact organization admin for help with archiving domains." -#: src/tags/mutations/create-tag.js:136 +#: src/tags/mutations/create-tag.js:131 msgid "Permission Denied: Please contact organization admin for help with creating tag." msgstr "Permission Denied: Please contact organization admin for help with creating tag." -#: src/domain/mutations/remove-domain.js:95 +#: src/domain/mutations/remove-domain.js:96 msgid "Permission Denied: Please contact organization admin for help with removing domain." msgstr "Permission Denied: Please contact organization admin for help with removing domain." @@ -400,26 +404,26 @@ msgstr "Permission Denied: Please contact organization admin for help with remov msgid "Permission Denied: Please contact organization admin for help with removing domains." msgstr "Permission Denied: Please contact organization admin for help with removing domains." -#: src/organization/mutations/remove-organization.js:70 +#: src/organization/mutations/remove-organization.js:67 msgid "Permission Denied: Please contact organization admin for help with removing organization." msgstr "Permission Denied: Please contact organization admin for help with removing organization." -#: src/affiliation/mutations/remove-user-from-org.js:127 -#: src/affiliation/mutations/remove-user-from-org.js:139 +#: src/affiliation/mutations/remove-user-from-org.js:128 +#: src/affiliation/mutations/remove-user-from-org.js:140 msgid "Permission Denied: Please contact organization admin for help with removing users." msgstr "Permission Denied: Please contact organization admin for help with removing users." -#: src/domain/mutations/update-domains-by-domain-ids.js:80 -#: src/domain/mutations/update-domains-by-filters.js:88 +#: src/domain/mutations/update-domains-by-domain-ids.js:81 +#: src/domain/mutations/update-domains-by-filters.js:89 msgid "Permission Denied: Please contact organization admin for help with updating domains." msgstr "Permission Denied: Please contact organization admin for help with updating domains." -#: src/organization/mutations/update-organization.js:155 +#: src/organization/mutations/update-organization.js:152 msgid "Permission Denied: Please contact organization admin for help with updating organization." msgstr "Permission Denied: Please contact organization admin for help with updating organization." -#: src/tags/mutations/update-tag.js:146 -#: src/tags/mutations/update-tag.js:157 +#: src/tags/mutations/update-tag.js:125 +#: src/tags/mutations/update-tag.js:136 msgid "Permission Denied: Please contact organization admin for help with updating tag." msgstr "Permission Denied: Please contact organization admin for help with updating tag." @@ -429,17 +433,15 @@ msgstr "Permission Denied: Please contact organization admin for help with updat #~ msgid "Permission Denied: Please contact organization admin for help with updating user roles." #~ msgstr "Permission Denied: Please contact organization admin for help with updating user roles." -#: src/affiliation/mutations/invite-user-to-org.js:102 +#: src/affiliation/mutations/invite-user-to-org.js:99 msgid "Permission Denied: Please contact organization admin for help with user invitations." msgstr "Permission Denied: Please contact organization admin for help with user invitations." -#: src/affiliation/mutations/update-user-role.js:110 -#: src/affiliation/mutations/update-user-role.js:161 -#: src/affiliation/mutations/update-user-role.js:173 +#: src/affiliation/mutations/update-user-role.js:112 msgid "Permission Denied: Please contact organization admin for help with user role changes." msgstr "Permission Denied: Please contact organization admin for help with user role changes." -#: src/domain/mutations/create-domain.js:121 +#: src/domain/mutations/create-domain.js:130 msgid "Permission Denied: Please contact organization user for help with creating domain." msgstr "Permission Denied: Please contact organization user for help with creating domain." @@ -452,29 +454,29 @@ msgstr "Permission Denied: Please contact organization user for help with creati #~ msgstr "Permission Denied: Please contact organization user for help with retrieving tags." #: src/domain/queries/find-domain-by-domain.js:51 -#: src/organization/objects/organization.js:198 +#: src/organization/objects/organization.js:195 msgid "Permission Denied: Please contact organization user for help with retrieving this domain." msgstr "Permission Denied: Please contact organization user for help with retrieving this domain." #: src/domain/mutations/request-discovery.js:98 -#: src/domain/mutations/request-scan.js:65 +#: src/domain/mutations/request-scan.js:66 msgid "Permission Denied: Please contact organization user for help with scanning this domain." msgstr "Permission Denied: Please contact organization user for help with scanning this domain." -#: src/domain/mutations/update-domain.js:137 +#: src/domain/mutations/update-domain.js:151 msgid "Permission Denied: Please contact organization user for help with updating this domain." msgstr "Permission Denied: Please contact organization user for help with updating this domain." -#: src/organization/mutations/archive-organization.js:69 +#: src/organization/mutations/archive-organization.js:66 msgid "Permission Denied: Please contact super admin for help with archiving organization." msgstr "Permission Denied: Please contact super admin for help with archiving organization." -#: src/domain/mutations/remove-domain.js:108 +#: src/domain/mutations/remove-domain.js:109 #: src/domain/mutations/remove-organizations-domains.js:106 msgid "Permission Denied: Please contact super admin for help with removing domain." msgstr "Permission Denied: Please contact super admin for help with removing domain." -#: src/organization/mutations/remove-organization.js:83 +#: src/organization/mutations/remove-organization.js:80 msgid "Permission Denied: Please contact super admin for help with removing organization." msgstr "Permission Denied: Please contact super admin for help with removing organization." @@ -482,18 +484,26 @@ msgstr "Permission Denied: Please contact super admin for help with removing org #~ msgid "Permission Denied: Please contact super admin for help with scanning this domain." #~ msgstr "Permission Denied: Please contact super admin for help with scanning this domain." -#: src/tags/mutations/update-tag.js:168 +#: src/tags/mutations/update-tag.js:147 msgid "Permission Denied: Please contact super admin for help with updating tag." msgstr "Permission Denied: Please contact super admin for help with updating tag." -#: src/organization/mutations/verify-organization.js:68 +#: src/affiliation/mutations/invite-user-to-org.js:112 +msgid "Permission Denied: Please contact super admin for help with user invitations." +msgstr "Permission Denied: Please contact super admin for help with user invitations." + +#: src/affiliation/mutations/update-user-role.js:167 +msgid "Permission Denied: Please contact super admin for help with user role changes." +msgstr "Permission Denied: Please contact super admin for help with user role changes." + +#: src/organization/mutations/verify-organization.js:65 msgid "Permission Denied: Please contact super admin for help with verifying this organization." msgstr "Permission Denied: Please contact super admin for help with verifying this organization." -#: src/auth/check-user-is-admin-for-user.js:20 -#: src/auth/check-user-is-admin-for-user.js:30 -#: src/auth/check-user-is-admin-for-user.js:63 -#: src/auth/check-user-is-admin-for-user.js:73 +#: src/auth/checks/check-user-is-admin-for-user.js:20 +#: src/auth/checks/check-user-is-admin-for-user.js:30 +#: src/auth/checks/check-user-is-admin-for-user.js:63 +#: src/auth/checks/check-user-is-admin-for-user.js:73 msgid "Permission error, not an admin for this user." msgstr "Permission error, not an admin for this user." @@ -501,7 +511,7 @@ msgstr "Permission error, not an admin for this user." msgid "Permission error: Unable to close other user's account." msgstr "Permission error: Unable to close other user's account." -#: src/auth/super-admin-required.js:11 +#: src/auth/guards/super-admin-required.js:11 msgid "Permissions error. You do not have sufficient permissions to access this data." msgstr "Permissions error. You do not have sufficient permissions to access this data." @@ -563,8 +573,8 @@ msgstr "Requesting `{amount}` records on the `DmarcFailureTable` connection exce msgid "Requesting `{amount}` records on the `DmarcSummaries` connection exceeds the `{argSet}` limit of 100 records." msgstr "Requesting `{amount}` records on the `DmarcSummaries` connection exceeds the `{argSet}` limit of 100 records." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:163 -#: src/domain/loaders/load-domain-connections-by-user-id.js:190 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:164 +#: src/domain/loaders/load-domain-connections-by-user-id.js:191 msgid "Requesting `{amount}` records on the `Domain` connection exceeds the `{argSet}` limit of 100 records." msgstr "Requesting `{amount}` records on the `Domain` connection exceeds the `{argSet}` limit of 100 records." @@ -618,7 +628,7 @@ msgstr "Successfully added {domainCount} domain(s) to {0}." #~ msgstr "Successfully added {domainCount} domains to {0}." #. placeholder {0}: organization.slug -#: src/organization/mutations/archive-organization.js:195 +#: src/organization/mutations/archive-organization.js:100 msgid "Successfully archived organization: {0}." msgstr "Successfully archived organization: {0}." @@ -627,7 +637,7 @@ msgstr "Successfully archived organization: {0}." msgid "Successfully closed account." msgstr "Successfully closed account." -#: src/domain/mutations/request-scan.js:174 +#: src/domain/mutations/request-scan.js:175 msgid "Successfully dispatched one time scan." msgstr "Successfully dispatched one time scan." @@ -643,7 +653,7 @@ msgstr "Successfully dispatched subdomain discovery scan." msgid "Successfully email verified account." msgstr "Successfully email verified account." -#: src/affiliation/mutations/invite-user-to-org.js:288 +#: src/affiliation/mutations/invite-user-to-org.js:282 msgid "Successfully invited user to organization, and sent notification email." msgstr "Successfully invited user to organization, and sent notification email." @@ -663,7 +673,7 @@ msgstr "Successfully removed {domainCount} domain(s) from {0}." #. placeholder {0}: domain.domain #. placeholder {1}: org.slug -#: src/domain/mutations/remove-domain.js:372 +#: src/domain/mutations/remove-domain.js:373 msgid "Successfully removed domain: {0} from {1}." msgstr "Successfully removed domain: {0} from {1}." @@ -673,19 +683,19 @@ msgid "Successfully removed domain: {0} from favourites." msgstr "Successfully removed domain: {0} from favourites." #. placeholder {0}: organization.slug -#: src/organization/mutations/remove-organization.js:418 +#: src/organization/mutations/remove-organization.js:107 msgid "Successfully removed organization: {0}." msgstr "Successfully removed organization: {0}." -#: src/affiliation/mutations/remove-user-from-org.js:200 +#: src/affiliation/mutations/remove-user-from-org.js:201 msgid "Successfully removed user from organization." msgstr "Successfully removed user from organization." -#: src/affiliation/mutations/request-org-affiliation.js:247 +#: src/affiliation/mutations/request-org-affiliation.js:231 msgid "Successfully requested invite to organization, and sent notification email." msgstr "Successfully requested invite to organization, and sent notification email." -#: src/affiliation/mutations/invite-user-to-org.js:176 +#: src/affiliation/mutations/invite-user-to-org.js:170 msgid "Successfully sent invitation to service, and organization email." msgstr "Successfully sent invitation to service, and organization email." @@ -701,13 +711,13 @@ msgstr "Successfully transferred org: {0} ownership to user: {1}" #. placeholder {0}: org.slug #. placeholder {1}: tags.join(', ') -#: src/domain/mutations/update-domains-by-domain-ids.js:178 -#: src/domain/mutations/update-domains-by-filters.js:309 +#: src/domain/mutations/update-domains-by-domain-ids.js:179 +#: src/domain/mutations/update-domains-by-filters.js:310 msgid "Successfully updated {domainCount} domain(s) in {0} with {1}." msgstr "Successfully updated {domainCount} domain(s) in {0} with {1}." #. placeholder {0}: currentOrg.slug -#: src/organization/mutations/verify-organization.js:138 +#: src/organization/mutations/verify-organization.js:90 msgid "Successfully verified organization: {0}." msgstr "Successfully verified organization: {0}." @@ -719,9 +729,9 @@ msgstr "Successfully verified phone number, and set TFA send method to text." #~ msgid "Tag label already in use, please choose another and try again." #~ msgstr "Tag label already in use, please choose another and try again." -#: src/tags/mutations/create-tag.js:96 -#: src/tags/mutations/create-tag.js:153 -#: src/tags/mutations/update-tag.js:182 +#: src/tags/mutations/create-tag.js:94 +#: src/tags/mutations/create-tag.js:148 +#: src/tags/mutations/update-tag.js:161 msgid "Tag label already in use. Please try again with a different label." msgstr "Tag label already in use. Please try again with a different label." @@ -754,15 +764,14 @@ msgstr "Unable leave organization. Please try again." msgid "Unable to add domains in unknown organization." msgstr "Unable to add domains in unknown organization." -#: src/organization/mutations/archive-organization.js:103 -#: src/organization/mutations/archive-organization.js:114 -#: src/organization/mutations/archive-organization.js:133 -#: src/organization/mutations/archive-organization.js:151 -#: src/organization/mutations/archive-organization.js:161 +#: src/organization/data-source.js:179 +#: src/organization/data-source.js:194 +#: src/organization/data-source.js:209 +#: src/organization/data-source.js:217 msgid "Unable to archive organization. Please try again." msgstr "Unable to archive organization. Please try again." -#: src/organization/mutations/archive-organization.js:55 +#: src/organization/mutations/archive-organization.js:52 msgid "Unable to archive unknown organization." msgstr "Unable to archive unknown organization." @@ -773,10 +782,12 @@ msgstr "Unable to archive unknown organization." msgid "Unable to authenticate. Please try again." msgstr "Unable to authenticate. Please try again." -#: src/auth/check-permission.js:26 -#: src/auth/check-permission.js:64 -#: src/auth/check-super-admin.js:20 -#: src/auth/check-super-admin.js:30 +#: src/auth/checks/check-permission.js:26 +#: src/auth/checks/check-permission.js:64 +#: src/auth/checks/check-super-admin.js:20 +#: src/auth/checks/check-super-admin.js:30 +#: src/auth/loaders/load-permission-by-org-id.js:27 +#: src/auth/loaders/load-permission-by-org-id.js:73 msgid "Unable to check permission. Please try again." msgstr "Unable to check permission. Please try again." @@ -798,20 +809,20 @@ msgstr "Unable to close account. Please try again." msgid "Unable to confirm completion of the tour. Please try again." msgstr "Unable to confirm completion of the tour. Please try again." -#: src/domain/mutations/create-domain.js:107 +#: src/domain/mutations/create-domain.js:116 msgid "Unable to create domain in unknown organization." msgstr "Unable to create domain in unknown organization." -#: src/domain/mutations/create-domain.js:178 +#: src/domain/mutations/create-domain.js:199 msgid "Unable to create domain, organization has already claimed it." msgstr "Unable to create domain, organization has already claimed it." -#: src/domain/mutations/create-domain.js:160 -#: src/domain/mutations/create-domain.js:168 -#: src/domain/mutations/create-domain.js:200 -#: src/domain/mutations/create-domain.js:209 -#: src/domain/mutations/create-domain.js:229 -#: src/domain/mutations/create-domain.js:237 +#: src/domain/mutations/create-domain.js:181 +#: src/domain/mutations/create-domain.js:189 +#: src/domain/mutations/create-domain.js:221 +#: src/domain/mutations/create-domain.js:230 +#: src/domain/mutations/create-domain.js:250 +#: src/domain/mutations/create-domain.js:258 msgid "Unable to create domain. Please try again." msgstr "Unable to create domain. Please try again." @@ -819,22 +830,22 @@ msgstr "Unable to create domain. Please try again." msgid "Unable to create domains. Please try again." msgstr "Unable to create domains. Please try again." -#: src/organization/mutations/create-organization.js:185 -#: src/organization/mutations/create-organization.js:206 -#: src/organization/mutations/create-organization.js:216 +#: src/organization/data-source.js:58 +#: src/organization/data-source.js:76 +#: src/organization/data-source.js:84 msgid "Unable to create organization. Please try again." msgstr "Unable to create organization. Please try again." -#: src/tags/mutations/create-tag.js:124 +#: src/tags/mutations/create-tag.js:119 msgid "Unable to create tag in unknown organization." msgstr "Unable to create tag in unknown organization." -#: src/tags/mutations/create-tag.js:113 +#: src/tags/mutations/create-tag.js:108 msgid "Unable to create tag, tagId already in use." msgstr "Unable to create tag, tagId already in use." -#: src/tags/mutations/create-tag.js:172 -#: src/tags/mutations/create-tag.js:180 +#: src/tags/data-source.js:58 +#: src/tags/data-source.js:65 msgid "Unable to create tag. Please try again." msgstr "Unable to create tag. Please try again." @@ -853,8 +864,7 @@ msgstr "Unable to dismiss message. Please try again." #~ msgid "Unable to dispatch one time scan. Please try again." #~ msgstr "Unable to dispatch one time scan. Please try again." -#: src/organization/objects/organization.js:275 -#: src/organization/objects/organization.js:285 +#: src/organization/objects/organization.js:265 msgid "Unable to export organization. Please try again." msgstr "Unable to export organization. Please try again." @@ -973,26 +983,25 @@ msgstr "Unable to find verified organization(s). Please try again." msgid "Unable to ignore CVE. Please try again." msgstr "Unable to ignore CVE. Please try again." -#: src/affiliation/mutations/invite-user-to-org.js:120 -#: src/affiliation/mutations/invite-user-to-org.js:130 -#: src/affiliation/mutations/invite-user-to-org.js:196 +#: src/affiliation/mutations/invite-user-to-org.js:124 +#: src/affiliation/mutations/invite-user-to-org.js:190 msgid "Unable to invite user to organization. Please try again." msgstr "Unable to invite user to organization. Please try again." -#: src/affiliation/mutations/invite-user-to-org.js:208 +#: src/affiliation/mutations/invite-user-to-org.js:202 msgid "Unable to invite user to organization. User is already affiliated with organization." msgstr "Unable to invite user to organization. User is already affiliated with organization." -#: src/affiliation/mutations/invite-user-to-org.js:83 +#: src/affiliation/mutations/invite-user-to-org.js:84 msgid "Unable to invite user to unknown organization." msgstr "Unable to invite user to unknown organization." -#: src/affiliation/mutations/invite-user-to-org.js:238 -#: src/affiliation/mutations/invite-user-to-org.js:259 +#: src/affiliation/mutations/invite-user-to-org.js:232 +#: src/affiliation/mutations/invite-user-to-org.js:253 msgid "Unable to invite user. Please try again." msgstr "Unable to invite user. Please try again." -#: src/affiliation/mutations/invite-user-to-org.js:69 +#: src/affiliation/mutations/invite-user-to-org.js:70 msgid "Unable to invite yourself to an org." msgstr "Unable to invite yourself to an org." @@ -1010,7 +1019,7 @@ msgstr "Unable to leave undefined organization." msgid "Unable to load additional findings. Please try again." msgstr "Unable to load additional findings. Please try again." -#: src/auth/check-user-belongs-to-org.js:20 +#: src/auth/checks/check-user-belongs-to-org.js:20 msgid "Unable to load affiliation information. Please try again." msgstr "Unable to load affiliation information. Please try again." @@ -1055,8 +1064,8 @@ msgstr "Unable to load DKIM guidance tag(s). Please try again." #~ msgstr "Unable to load DKIM scan(s). Please try again." #: src/summaries/queries/dkim-summary.js:12 -msgid "Unable to load DKIM summary. Please try again." -msgstr "Unable to load DKIM summary. Please try again." +#~ msgid "Unable to load DKIM summary. Please try again." +#~ msgstr "Unable to load DKIM summary. Please try again." #: src/dmarc-summaries/loaders/load-dmarc-failure-connections-by-sum-id.js:13 #: src/dmarc-summaries/loaders/load-dmarc-failure-connections-by-sum-id.js:141 @@ -1070,8 +1079,8 @@ msgid "Unable to load DMARC guidance tag(s). Please try again." msgstr "Unable to load DMARC guidance tag(s). Please try again." #: src/summaries/queries/dmarc-phase-summary.js:12 -msgid "Unable to load DMARC phase summary. Please try again." -msgstr "Unable to load DMARC phase summary. Please try again." +#~ msgid "Unable to load DMARC phase summary. Please try again." +#~ msgstr "Unable to load DMARC phase summary. Please try again." #: src/email-scan/loaders/load-dmarc-connections-by-domain-id.js:319 #: src/email-scan/loaders/load-dmarc-connections-by-domain-id.js:331 @@ -1088,13 +1097,11 @@ msgid "Unable to load DMARC summary data. Please try again." msgstr "Unable to load DMARC summary data. Please try again." #: src/summaries/queries/dmarc-summary.js:12 -msgid "Unable to load DMARC summary. Please try again." -msgstr "Unable to load DMARC summary. Please try again." +#~ msgid "Unable to load DMARC summary. Please try again." +#~ msgstr "Unable to load DMARC summary. Please try again." #: src/dns-scan/loaders/load-dns-connections-by-domain-id.js:154 #: src/dns-scan/loaders/load-dns-connections-by-domain-id.js:164 -#: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:156 -#: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:166 msgid "Unable to load DNS scan(s). Please try again." msgstr "Unable to load DNS scan(s). Please try again." @@ -1110,9 +1117,9 @@ msgstr "Unable to load domain selector(s). Please try again." msgid "Unable to load domain. Please try again." msgstr "Unable to load domain. Please try again." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:523 -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:533 -#: src/domain/loaders/load-domain-connections-by-user-id.js:575 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:402 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:412 +#: src/domain/loaders/load-domain-connections-by-user-id.js:469 #: src/user/loaders/load-my-tracker-by-user-id.js:33 msgid "Unable to load domain(s). Please try again." msgstr "Unable to load domain(s). Please try again." @@ -1140,8 +1147,8 @@ msgstr "Unable to load HTTPS guidance tag(s). Please try again." #~ msgstr "Unable to load HTTPS scan(s). Please try again." #: src/summaries/queries/https-summary.js:13 -msgid "Unable to load HTTPS summary. Please try again." -msgstr "Unable to load HTTPS summary. Please try again." +#~ msgid "Unable to load HTTPS summary. Please try again." +#~ msgstr "Unable to load HTTPS summary. Please try again." #: src/audit-logs/loaders/load-audit-log-by-key.js:19 #: src/audit-logs/loaders/load-audit-log-by-key.js:31 @@ -1153,20 +1160,32 @@ msgid "Unable to load log(s). Please try again." msgstr "Unable to load log(s). Please try again." #: src/summaries/queries/mail-summary.js:12 -msgid "Unable to load mail summary. Please try again." -msgstr "Unable to load mail summary. Please try again." +#~ msgid "Unable to load mail summary. Please try again." +#~ msgstr "Unable to load mail summary. Please try again." #: src/additional-findings/loaders/load-top-25-reports.js:29 #: src/organization/loaders/load-all-organization-domain-statuses.js:164 -#: src/organization/loaders/load-organization-domain-statuses.js:166 +#: src/organization/loaders/load-organization-domain-statuses.js:172 msgid "Unable to load organization domain statuses. Please try again." msgstr "Unable to load organization domain statuses. Please try again." +#: src/organization/loaders/load-organization-names-by-id.js:19 +#: src/organization/loaders/load-organization-names-by-id.js:29 +msgid "Unable to load organization names. Please try again." +msgstr "Unable to load organization names. Please try again." + #: src/organization/loaders/load-organization-summaries-by-period.js:56 #: src/organization/loaders/load-organization-summaries-by-period.js:66 msgid "Unable to load organization summary data. Please try again." msgstr "Unable to load organization summary data. Please try again." +#: src/organization/data-source.js:117 +#: src/organization/data-source.js:124 +#: src/organization/data-source.js:144 +#: src/organization/data-source.js:152 +msgid "Unable to load organization. Please try again." +msgstr "Unable to load organization. Please try again." + #: src/organization/loaders/load-organization-by-key.js:31 #: src/organization/loaders/load-organization-by-key.js:41 #: src/organization/loaders/load-organization-by-slug.js:34 @@ -1178,8 +1197,10 @@ msgstr "Unable to load organization summary data. Please try again." msgid "Unable to load organization(s). Please try again." msgstr "Unable to load organization(s). Please try again." -#: src/auth/check-org-owner.js:19 -#: src/auth/check-org-owner.js:27 +#: src/auth/checks/check-org-owner.js:19 +#: src/auth/checks/check-org-owner.js:27 +#: src/auth/loaders/load-org-owner-by-org-id.js:23 +#: src/auth/loaders/load-org-owner-by-org-id.js:33 msgid "Unable to load owner information. Please try again." msgstr "Unable to load owner information. Please try again." @@ -1200,8 +1221,8 @@ msgstr "Unable to load SPF guidance tag(s). Please try again." #~ msgstr "Unable to load SPF scan(s). Please try again." #: src/summaries/queries/spf-summary.js:12 -msgid "Unable to load SPF summary. Please try again." -msgstr "Unable to load SPF summary. Please try again." +#~ msgid "Unable to load SPF summary. Please try again." +#~ msgstr "Unable to load SPF summary. Please try again." #: src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js:260 #: src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js:272 @@ -1214,13 +1235,13 @@ msgstr "Unable to load SSL guidance tag(s). Please try again." #~ msgstr "Unable to load SSL scan(s). Please try again." #: src/summaries/queries/ssl-summary.js:12 -msgid "Unable to load SSL summary. Please try again." -msgstr "Unable to load SSL summary. Please try again." +#~ msgid "Unable to load SSL summary. Please try again." +#~ msgstr "Unable to load SSL summary. Please try again." #: src/summaries/loaders/load-chart-summary-by-key.js:17 #: src/summaries/loaders/load-chart-summary-by-key.js:25 -msgid "Unable to load summary. Please try again." -msgstr "Unable to load summary. Please try again." +#~ msgid "Unable to load summary. Please try again." +#~ msgstr "Unable to load summary. Please try again." #: src/tags/loaders/load-all-tags.js:36 #: src/tags/loaders/load-all-tags.js:44 @@ -1266,8 +1287,8 @@ msgid "Unable to load verified rua domains. Please try again." msgstr "Unable to load verified rua domains. Please try again." #: src/summaries/queries/web-connections-summary.js:12 -msgid "Unable to load web connections summary. Please try again." -msgstr "Unable to load web connections summary. Please try again." +#~ msgid "Unable to load web connections summary. Please try again." +#~ msgstr "Unable to load web connections summary. Please try again." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:169 #: src/web-scan/loaders/load-web-connections-by-domain-id.js:179 @@ -1278,15 +1299,15 @@ msgid "Unable to load web scan(s). Please try again." msgstr "Unable to load web scan(s). Please try again." #: src/summaries/queries/web-summary.js:13 -msgid "Unable to load web summary. Please try again." -msgstr "Unable to load web summary. Please try again." +#~ msgid "Unable to load web summary. Please try again." +#~ msgstr "Unable to load web summary. Please try again." #: src/affiliation/loaders/load-affiliation-connections-by-org-id.js:293 #: src/affiliation/loaders/load-affiliation-connections-by-user-id.js:437 msgid "Unable to query affiliation(s). Please try again." msgstr "Unable to query affiliation(s). Please try again." -#: src/domain/loaders/load-domain-connections-by-user-id.js:565 +#: src/domain/loaders/load-domain-connections-by-user-id.js:459 #: src/user/loaders/load-my-tracker-by-user-id.js:23 msgid "Unable to query domain(s). Please try again." msgstr "Unable to query domain(s). Please try again." @@ -1309,29 +1330,29 @@ msgstr "Unable to query user(s). Please try again." msgid "Unable to refresh tokens, please sign in." msgstr "Unable to refresh tokens, please sign in." -#: src/affiliation/mutations/remove-user-from-org.js:105 +#: src/affiliation/mutations/remove-user-from-org.js:106 msgid "Unable to remove a user that already does not belong to this organization." msgstr "Unable to remove a user that already does not belong to this organization." -#: src/domain/mutations/remove-domain.js:81 +#: src/domain/mutations/remove-domain.js:82 msgid "Unable to remove domain from unknown organization." msgstr "Unable to remove domain from unknown organization." -#: src/domain/mutations/remove-domain.js:137 +#: src/domain/mutations/remove-domain.js:138 msgid "Unable to remove domain. Domain is not part of organization." msgstr "Unable to remove domain. Domain is not part of organization." -#: src/domain/mutations/remove-domain.js:124 -#: src/domain/mutations/remove-domain.js:153 -#: src/domain/mutations/remove-domain.js:187 -#: src/domain/mutations/remove-domain.js:207 -#: src/domain/mutations/remove-domain.js:236 -#: src/domain/mutations/remove-domain.js:255 -#: src/domain/mutations/remove-domain.js:273 -#: src/domain/mutations/remove-domain.js:290 -#: src/domain/mutations/remove-domain.js:308 -#: src/domain/mutations/remove-domain.js:332 -#: src/domain/mutations/remove-domain.js:344 +#: src/domain/mutations/remove-domain.js:125 +#: src/domain/mutations/remove-domain.js:154 +#: src/domain/mutations/remove-domain.js:188 +#: src/domain/mutations/remove-domain.js:208 +#: src/domain/mutations/remove-domain.js:237 +#: src/domain/mutations/remove-domain.js:256 +#: src/domain/mutations/remove-domain.js:274 +#: src/domain/mutations/remove-domain.js:291 +#: src/domain/mutations/remove-domain.js:309 +#: src/domain/mutations/remove-domain.js:333 +#: src/domain/mutations/remove-domain.js:345 msgid "Unable to remove domain. Please try again." msgstr "Unable to remove domain. Please try again." @@ -1339,19 +1360,17 @@ msgstr "Unable to remove domain. Please try again." msgid "Unable to remove domains from unknown organization." msgstr "Unable to remove domains from unknown organization." -#: src/organization/mutations/remove-organization.js:103 -#: src/organization/mutations/remove-organization.js:114 -#: src/organization/mutations/remove-organization.js:145 -#: src/organization/mutations/remove-organization.js:161 -#: src/organization/mutations/remove-organization.js:192 -#: src/organization/mutations/remove-organization.js:203 -#: src/organization/mutations/remove-organization.js:230 -#: src/organization/mutations/remove-organization.js:249 -#: src/organization/mutations/remove-organization.js:267 -#: src/organization/mutations/remove-organization.js:284 -#: src/organization/mutations/remove-organization.js:317 -#: src/organization/mutations/remove-organization.js:382 -#: src/organization/mutations/remove-organization.js:392 +#: src/organization/data-source.js:278 +#: src/organization/data-source.js:307 +#: src/organization/data-source.js:321 +#: src/organization/data-source.js:350 +#: src/organization/data-source.js:374 +#: src/organization/data-source.js:390 +#: src/organization/data-source.js:405 +#: src/organization/data-source.js:419 +#: src/organization/data-source.js:448 +#: src/organization/data-source.js:490 +#: src/organization/data-source.js:498 msgid "Unable to remove organization. Please try again." msgstr "Unable to remove organization. Please try again." @@ -1360,15 +1379,15 @@ msgstr "Unable to remove organization. Please try again." msgid "Unable to remove phone number. Please try again." msgstr "Unable to remove phone number. Please try again." -#: src/domain/mutations/remove-domain.js:66 +#: src/domain/mutations/remove-domain.js:67 msgid "Unable to remove unknown domain." msgstr "Unable to remove unknown domain." -#: src/organization/mutations/remove-organization.js:55 +#: src/organization/mutations/remove-organization.js:52 msgid "Unable to remove unknown organization." msgstr "Unable to remove unknown organization." -#: src/affiliation/mutations/remove-user-from-org.js:78 +#: src/affiliation/mutations/remove-user-from-org.js:79 msgid "Unable to remove unknown user from organization." msgstr "Unable to remove unknown user from organization." @@ -1376,26 +1395,26 @@ msgstr "Unable to remove unknown user from organization." #~ msgid "Unable to remove user from organization." #~ msgstr "Unable to remove user from organization." -#: src/affiliation/mutations/remove-user-from-org.js:95 -#: src/affiliation/mutations/remove-user-from-org.js:116 -#: src/affiliation/mutations/remove-user-from-org.js:163 -#: src/affiliation/mutations/remove-user-from-org.js:173 +#: src/affiliation/mutations/remove-user-from-org.js:96 +#: src/affiliation/mutations/remove-user-from-org.js:117 +#: src/affiliation/mutations/remove-user-from-org.js:164 +#: src/affiliation/mutations/remove-user-from-org.js:174 msgid "Unable to remove user from this organization. Please try again." msgstr "Unable to remove user from this organization. Please try again." -#: src/affiliation/mutations/remove-user-from-org.js:62 +#: src/affiliation/mutations/remove-user-from-org.js:63 msgid "Unable to remove user from unknown organization." msgstr "Unable to remove user from unknown organization." -#: src/domain/mutations/request-scan.js:119 +#: src/domain/mutations/request-scan.js:120 msgid "Unable to request a one time scan on a domain that already has a pending scan." msgstr "Unable to request a one time scan on a domain that already has a pending scan." -#: src/domain/mutations/request-scan.js:54 +#: src/domain/mutations/request-scan.js:55 msgid "Unable to request a one time scan on an unknown domain." msgstr "Unable to request a one time scan on an unknown domain." -#: src/domain/mutations/request-scan.js:127 +#: src/domain/mutations/request-scan.js:128 msgid "Unable to request a one time scan. Please try again." msgstr "Unable to request a one time scan. Please try again." @@ -1423,9 +1442,8 @@ msgstr "Unable to request invite to unknown organization." #: src/affiliation/mutations/request-org-affiliation.js:124 #: src/affiliation/mutations/request-org-affiliation.js:141 #: src/affiliation/mutations/request-org-affiliation.js:152 -#: src/affiliation/mutations/request-org-affiliation.js:173 -#: src/affiliation/mutations/request-org-affiliation.js:183 -#: src/affiliation/mutations/request-org-affiliation.js:214 +#: src/affiliation/mutations/request-org-affiliation.js:167 +#: src/affiliation/mutations/request-org-affiliation.js:198 msgid "Unable to request invite. Please try again." msgstr "Unable to request invite. Please try again." @@ -1439,8 +1457,8 @@ msgstr "Unable to request invite. Please try again." msgid "Unable to reset password. Please try again." msgstr "Unable to reset password. Please try again." -#: src/domain/objects/domain.js:324 -#: src/domain/objects/domain.js:359 +#: src/domain/objects/domain.js:274 +#: src/domain/objects/domain.js:309 msgid "Unable to retrieve DMARC report information for: {domain}" msgstr "Unable to retrieve DMARC report information for: {domain}" @@ -1470,6 +1488,10 @@ msgstr "Unable to send org invite request email. Please try again." msgid "Unable to send password reset email. Please try again." msgstr "Unable to send password reset email. Please try again." +#: src/notify/notify-send-role-change-email.js:21 +#~ msgid "Unable to send role update email. Please try again." +#~ msgstr "Unable to send role update email. Please try again." + #: src/notify/notify-send-tfa-text-msg.js:30 #~ msgid "Unable to send two factor authentication message. Please try again." #~ msgstr "Unable to send two factor authentication message. Please try again." @@ -1565,40 +1587,36 @@ msgstr "Unable to unfavourite unknown domain." #~ msgid "Unable to unignore CVE. Please try again." #~ msgstr "Unable to unignore CVE. Please try again." -#: src/domain/mutations/update-domain.js:236 +#: src/domain/mutations/update-domain.js:261 msgid "Unable to update domain edge. Please try again." msgstr "Unable to update domain edge. Please try again." -#: src/domain/mutations/update-domain.js:123 +#: src/domain/mutations/update-domain.js:137 msgid "Unable to update domain in an unknown org." msgstr "Unable to update domain in an unknown org." -#: src/domain/mutations/update-domain.js:164 +#: src/domain/mutations/update-domain.js:178 msgid "Unable to update domain that does not belong to the given organization." msgstr "Unable to update domain that does not belong to the given organization." -#: src/domain/mutations/update-domain.js:154 -#: src/domain/mutations/update-domain.js:193 -#: src/domain/mutations/update-domain.js:247 +#: src/domain/mutations/update-domain.js:168 +#: src/domain/mutations/update-domain.js:218 +#: src/domain/mutations/update-domain.js:272 msgid "Unable to update domain. Please try again." msgstr "Unable to update domain. Please try again." -#: src/domain/mutations/update-domains-by-domain-ids.js:67 -#: src/domain/mutations/update-domains-by-filters.js:75 +#: src/domain/mutations/update-domains-by-domain-ids.js:68 +#: src/domain/mutations/update-domains-by-filters.js:76 msgid "Unable to update domains in unknown organization." msgstr "Unable to update domains in unknown organization." -#: src/domain/mutations/update-domains-by-filters.js:228 -#: src/domain/mutations/update-domains-by-filters.js:236 -#: src/domain/mutations/update-domains-by-filters.js:243 +#: src/domain/mutations/update-domains-by-filters.js:229 +#: src/domain/mutations/update-domains-by-filters.js:237 +#: src/domain/mutations/update-domains-by-filters.js:244 msgid "Unable to update domains. Please try again." msgstr "Unable to update domains. Please try again." -#: src/organization/mutations/update-organization.js:174 -#: src/organization/mutations/update-organization.js:200 -#: src/organization/mutations/update-organization.js:208 -#: src/organization/mutations/update-organization.js:262 -#: src/organization/mutations/update-organization.js:270 +#: src/organization/data-source.js:101 msgid "Unable to update organization. Please try again." msgstr "Unable to update organization. Please try again." @@ -1624,23 +1642,23 @@ msgstr "Unable to update password. Please try again." msgid "Unable to update profile. Please try again." msgstr "Unable to update profile. Please try again." -#: src/affiliation/mutations/update-user-role.js:95 +#: src/affiliation/mutations/update-user-role.js:97 msgid "Unable to update role: organization unknown." msgstr "Unable to update role: organization unknown." -#: src/affiliation/mutations/update-user-role.js:138 +#: src/affiliation/mutations/update-user-role.js:140 msgid "Unable to update role: user does not belong to organization." msgstr "Unable to update role: user does not belong to organization." -#: src/affiliation/mutations/update-user-role.js:81 +#: src/affiliation/mutations/update-user-role.js:83 msgid "Unable to update role: user unknown." msgstr "Unable to update role: user unknown." -#: src/tags/mutations/update-tag.js:134 +#: src/tags/mutations/update-tag.js:113 msgid "Unable to update tag in unknown organization." msgstr "Unable to update tag in unknown organization." -#: src/tags/mutations/update-tag.js:124 +#: src/tags/mutations/update-tag.js:103 msgid "Unable to update tag, orgId is invalid." msgstr "Unable to update tag, orgId is invalid." @@ -1648,33 +1666,34 @@ msgstr "Unable to update tag, orgId is invalid." #~ msgid "Unable to update tag, tagId already in use." #~ msgstr "Unable to update tag, tagId already in use." -#: src/tags/mutations/update-tag.js:90 -#: src/tags/mutations/update-tag.js:98 -#: src/tags/mutations/update-tag.js:221 -#: src/tags/mutations/update-tag.js:232 +#: src/tags/data-source.js:30 +#: src/tags/data-source.js:36 +#: src/tags/data-source.js:92 +#: src/tags/data-source.js:101 msgid "Unable to update tag. Please try again." msgstr "Unable to update tag. Please try again." -#: src/domain/mutations/update-domain.js:109 +#: src/domain/mutations/update-domain.js:123 msgid "Unable to update unknown domain." msgstr "Unable to update unknown domain." -#: src/organization/mutations/update-organization.js:140 +#: src/organization/mutations/update-organization.js:137 msgid "Unable to update unknown organization." msgstr "Unable to update unknown organization." -#: src/tags/mutations/update-tag.js:108 +#: src/tags/mutations/update-tag.js:87 msgid "Unable to update unknown tag." msgstr "Unable to update unknown tag." -#: src/affiliation/mutations/update-user-role.js:128 -#: src/affiliation/mutations/update-user-role.js:150 -#: src/affiliation/mutations/update-user-role.js:202 -#: src/affiliation/mutations/update-user-role.js:212 +#: src/affiliation/mutations/update-user-role.js:130 +#: src/affiliation/mutations/update-user-role.js:152 +#: src/affiliation/mutations/update-user-role.js:196 +#: src/affiliation/mutations/update-user-role.js:206 +#: src/affiliation/mutations/update-user-role.js:217 msgid "Unable to update user's role. Please try again." msgstr "Unable to update user's role. Please try again." -#: src/affiliation/mutations/update-user-role.js:67 +#: src/affiliation/mutations/update-user-role.js:69 msgid "Unable to update your own role." msgstr "Unable to update your own role." @@ -1694,17 +1713,17 @@ msgid "Unable to verify if user is a super admin, please try again." msgstr "Unable to verify if user is a super admin, please try again." #: src/user/mutations/update-user-profile.js:99 -#: src/user/queries/is-user-admin.js:55 +#: src/user/queries/is-user-admin.js:49 msgid "Unable to verify if user is an admin, please try again." msgstr "Unable to verify if user is an admin, please try again." -#: src/organization/mutations/verify-organization.js:106 -#: src/organization/mutations/verify-organization.js:123 -#: src/organization/mutations/verify-organization.js:131 +#: src/organization/data-source.js:237 +#: src/organization/data-source.js:252 +#: src/organization/data-source.js:260 msgid "Unable to verify organization. Please try again." msgstr "Unable to verify organization. Please try again." -#: src/organization/mutations/verify-organization.js:53 +#: src/organization/mutations/verify-organization.js:50 msgid "Unable to verify unknown organization." msgstr "Unable to verify unknown organization." @@ -1716,7 +1735,7 @@ msgstr "User could not be queried." msgid "User is trying to register for a non-production environment." msgstr "User is trying to register for a non-production environment." -#: src/affiliation/mutations/update-user-role.js:246 +#: src/affiliation/mutations/update-user-role.js:253 msgid "User role was updated successfully." msgstr "User role was updated successfully." @@ -1725,11 +1744,11 @@ msgstr "User role was updated successfully." msgid "Username not available, please try another." msgstr "Username not available, please try another." -#: src/auth/tfa-required.js:15 +#: src/auth/guards/tfa-required.js:15 msgid "Verification error. Please activate multi-factor authentication to access content." msgstr "Verification error. Please activate multi-factor authentication to access content." -#: src/auth/verified-required.js:15 +#: src/auth/guards/verified-required.js:15 msgid "Verification error. Please verify your account via email to access content." msgstr "Verification error. Please verify your account via email to access content." @@ -1766,8 +1785,8 @@ msgstr "You must provide a `first` or `last` value to properly paginate the `Dma msgid "You must provide a `first` or `last` value to properly paginate the `DmarcSummaries` connection." msgstr "You must provide a `first` or `last` value to properly paginate the `DmarcSummaries` connection." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:140 -#: src/domain/loaders/load-domain-connections-by-user-id.js:165 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:141 +#: src/domain/loaders/load-domain-connections-by-user-id.js:166 msgid "You must provide a `first` or `last` value to properly paginate the `Domain` connection." msgstr "You must provide a `first` or `last` value to properly paginate the `Domain` connection." @@ -1828,8 +1847,8 @@ msgid "You must provide a `limit` value in the range of 1-100 to properly pagina msgstr "You must provide a `limit` value in the range of 1-100 to properly paginate the `DNS` connection." #: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:16 -msgid "You must provide a `limit` value in the range of 1-100 to properly paginate the `MXRecord` connection." -msgstr "You must provide a `limit` value in the range of 1-100 to properly paginate the `MXRecord` connection." +#~ msgid "You must provide a `limit` value in the range of 1-100 to properly paginate the `MXRecord` connection." +#~ msgstr "You must provide a `limit` value in the range of 1-100 to properly paginate the `MXRecord` connection." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:16 msgid "You must provide a `limit` value in the range of 1-100 to properly paginate the `web` connection." @@ -1840,8 +1859,8 @@ msgid "You must provide a `limit` value to properly paginate the `DNS` connectio msgstr "You must provide a `limit` value to properly paginate the `DNS` connection." #: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:9 -msgid "You must provide a `limit` value to properly paginate the `MXRecord` connection." -msgstr "You must provide a `limit` value to properly paginate the `MXRecord` connection." +#~ msgid "You must provide a `limit` value to properly paginate the `MXRecord` connection." +#~ msgstr "You must provide a `limit` value to properly paginate the `MXRecord` connection." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:9 msgid "You must provide a `limit` value to properly paginate the `web` connection." @@ -1876,8 +1895,8 @@ msgid "You must provide at most one pagination method (`before`, `after`, `offse msgstr "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `DNS` connection." #: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:30 -msgid "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `MXRecord` connection." -msgstr "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `MXRecord` connection." +#~ msgid "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `MXRecord` connection." +#~ msgstr "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `MXRecord` connection." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:30 msgid "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `web` connection." diff --git a/api/src/locale/fr/messages.po b/api/src/locale/fr/messages.po index ae7a279220..d1672a6160 100644 --- a/api/src/locale/fr/messages.po +++ b/api/src/locale/fr/messages.po @@ -19,8 +19,8 @@ msgstr "" #: src/dmarc-summaries/loaders/load-dmarc-sum-connections-by-user-id.js:202 #: src/dmarc-summaries/loaders/load-full-pass-connections-by-sum-id.js:83 #: src/dmarc-summaries/loaders/load-spf-failure-connections-by-sum-id.js:83 -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:177 -#: src/domain/loaders/load-domain-connections-by-user-id.js:204 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:178 +#: src/domain/loaders/load-domain-connections-by-user-id.js:205 #: src/guidance-tag/loaders/load-aggregate-guidance-tags-connections.js:132 #: src/guidance-tag/loaders/load-dkim-guidance-tags-connections.js:136 #: src/guidance-tag/loaders/load-dmarc-guidance-tags-connections.js:136 @@ -66,8 +66,8 @@ msgstr "`{argSet}` sur la connexion `DmarcFailureTable` ne peut être inférieur msgid "`{argSet}` on the `DmarcSummaries` connection cannot be less than zero." msgstr "`{argSet}` sur la connexion `DmarcSummaries` ne peut être inférieur à zéro." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:156 -#: src/domain/loaders/load-domain-connections-by-user-id.js:181 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:157 +#: src/domain/loaders/load-domain-connections-by-user-id.js:182 msgid "`{argSet}` on the `Domain` connection cannot be less than zero." msgstr "`{argSet}` sur la connexion `Domain` ne peut être inférieur à zéro." @@ -123,33 +123,35 @@ msgstr "`{argSet}` sur la connexion `VerifiedDomain` ne peut être inférieur à msgid "`{argSet}` on the `VerifiedOrganization` connection cannot be less than zero." msgstr "`{argSet}` sur la connexion `VerifiedOrganization` ne peut être inférieur à zéro." -#: src/organization/objects/organization.js:244 +#: src/organization/objects/organization.js:240 #: src/organization/queries/get-all-organization-domain-statuses.js:69 msgid "Assess" msgstr "Évaluez" -#: src/auth/check-permission.js:18 -#: src/auth/check-permission.js:57 -#: src/auth/user-required.js:10 -#: src/auth/user-required.js:21 -#: src/auth/user-required.js:28 +#: src/auth/checks/check-permission.js:18 +#: src/auth/checks/check-permission.js:57 +#: src/auth/guards/user-required.js:10 +#: src/auth/guards/user-required.js:21 +#: src/auth/guards/user-required.js:28 +#: src/auth/loaders/load-permission-by-org-id.js:19 +#: src/auth/loaders/load-permission-by-org-id.js:63 msgid "Authentication error. Please sign in." msgstr "Erreur d'authentification. Veuillez vous connecter." -#: src/domain/objects/domain.js:279 +#: src/domain/objects/domain.js:229 msgid "Cannot query additional findings without permission." msgstr "Il n'est pas possible de demander des résultats supplémentaires sans autorisation." -#: src/organization/objects/organization.js:378 +#: src/organization/objects/organization.js:359 msgid "Cannot query affiliations on organization without admin permission or higher." msgstr "Impossible d'interroger les affiliations sur l'organisation sans l'autorisation de l'administrateur ou plus." #: src/audit-logs/loaders/load-audit-logs-by-org-id.js:224 -#: src/audit-logs/queries/find-audit-logs.js:51 +#: src/audit-logs/queries/find-audit-logs.js:53 msgid "Cannot query audit logs on organization without admin permission or higher." msgstr "Impossible d'interroger les journaux d'audit sur l'organisation sans l'autorisation d'administrateur ou plus." -#: src/domain/objects/domain.js:168 +#: src/domain/objects/domain.js:164 msgid "Cannot query dns scan results without permission." msgstr "Impossible d'interroger les résultats de l'analyse DNS sans autorisation." @@ -157,8 +159,7 @@ msgstr "Impossible d'interroger les résultats de l'analyse DNS sans autorisatio msgid "Cannot query domain selectors without permission." msgstr "Impossible d'interroger les sélecteurs de domaine sans autorisation." -#: src/domain/objects/domain.js:210 -#: src/domain/objects/domain.js:256 +#: src/domain/objects/domain.js:206 msgid "Cannot query web scan results without permission." msgstr "Impossible d'interroger les résultats de l'analyse web sans autorisation." @@ -170,22 +171,22 @@ msgstr "CVE est déjà ignoré pour ce domaine." msgid "CVE is not ignored for this domain." msgstr "Le CVE n'est pas ignoré dans ce domaine." -#: src/organization/objects/organization.js:246 +#: src/organization/objects/organization.js:242 #: src/organization/queries/get-all-organization-domain-statuses.js:71 msgid "Deploy" -msgstr Déployer +msgstr "msgstr Déployer" #: src/user/mutations/sign-up.js:111 msgid "Email already in use." msgstr "Courriel déjà utilisé." -#: src/organization/objects/organization.js:248 +#: src/organization/objects/organization.js:244 #: src/organization/queries/get-all-organization-domain-statuses.js:73 msgid "Enforce" msgstr "Appliquer" -#: src/domain/mutations/request-scan.js:89 -#: src/domain/mutations/request-scan.js:99 +#: src/domain/mutations/request-scan.js:90 +#: src/domain/mutations/request-scan.js:100 msgid "Error while requesting scan. Please try again." msgstr "Erreur lors de la demande d'analyse. Veuillez réessayer." @@ -212,11 +213,11 @@ msgstr "La valeur du jeton est incorrecte. Veuillez demander un nouvel e-mail." msgid "Incorrect username or password. Please try again." msgstr "Le nom d'utilisateur ou le mot de passe est incorrect. Veuillez réessayer." -#: src/auth/verify-jwt.js:15 +#: src/auth/utils/verify-jwt.js:15 msgid "Invalid token, please sign in." msgstr "Jeton invalide, veuillez vous connecter." -#: src/organization/objects/organization.js:250 +#: src/organization/objects/organization.js:246 #: src/organization/queries/get-all-organization-domain-statuses.js:75 msgid "Maintain" msgstr "Maintenir" @@ -229,7 +230,7 @@ msgstr "Message rejeté avec succès" msgid "New passwords do not match." msgstr "Les nouveaux mots de passe ne correspondent pas." -#: src/organization/queries/find-organization-by-slug.js:41 +#: src/organization/queries/find-organization-by-slug.js:42 #: src/user/queries/find-my-tracker.js:29 msgid "No organization with the provided slug could be found." msgstr "Aucune organisation avec le slug fourni n'a pu être trouvée." @@ -242,22 +243,22 @@ msgstr "Aucun domaine vérifié avec le domaine fourni n'a pu être trouvé." msgid "No verified organization with the provided slug could be found." msgstr "Aucune organisation vérifiée avec le slug fourni n'a pu être trouvée." -#: src/organization/mutations/verify-organization.js:81 +#: src/organization/mutations/verify-organization.js:78 msgid "Organization has already been verified." msgstr "L'organisation a déjà été vérifiée." -#: src/organization/mutations/update-organization.js:184 +#: src/organization/mutations/update-organization.js:167 msgid "Organization name already in use, please choose another and try again." msgstr "Le nom de l'organisation est déjà utilisé, veuillez en choisir un autre et réessayer." -#: src/organization/mutations/create-organization.js:125 +#: src/organization/mutations/create-organization.js:85 msgid "Organization name already in use. Please try again with a different name." msgstr "Le nom de l'organisation est déjà utilisé. Veuillez réessayer avec un nom différent." -#: src/auth/check-domain-ownership.js:29 -#: src/auth/check-domain-ownership.js:39 -#: src/auth/check-domain-ownership.js:65 -#: src/auth/check-domain-ownership.js:74 +#: src/auth/checks/check-domain-ownership.js:29 +#: src/auth/checks/check-domain-ownership.js:39 +#: src/auth/checks/check-domain-ownership.js:65 +#: src/auth/checks/check-domain-ownership.js:74 msgid "Ownership check error. Unable to request domain information." msgstr "Erreur de vérification de la propriété. Impossible de demander des informations sur le domaine." @@ -291,8 +292,8 @@ msgstr "Passer à la fois `first` et `last` pour paginer la connexion `DmarcFail msgid "Passing both `first` and `last` to paginate the `DmarcSummaries` connection is not supported." msgstr "Passer à la fois `first` et `last` pour paginer la connexion `DmarcSummaries` n'est pas supporté." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:147 -#: src/domain/loaders/load-domain-connections-by-user-id.js:172 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:148 +#: src/domain/loaders/load-domain-connections-by-user-id.js:173 msgid "Passing both `first` and `last` to paginate the `Domain` connection is not supported." msgstr "Passer à la fois `first` et `last` pour paginer la connexion `Domain` n'est pas supporté." @@ -365,14 +366,17 @@ msgstr "Le mot de passe a été mis à jour avec succès." msgid "Passwords do not match." msgstr "Les mots de passe ne correspondent pas." -#: src/auth/check-domain-permission.js:22 -#: src/auth/check-domain-permission.js:51 -#: src/auth/check-domain-permission.js:61 +#: src/auth/checks/check-domain-permission.js:22 +#: src/auth/checks/check-domain-permission.js:51 +#: src/auth/checks/check-domain-permission.js:61 +#: src/auth/loaders/load-domain-permission-by-domain-id.js:19 +#: src/auth/loaders/load-domain-permission-by-domain-id.js:51 +#: src/auth/loaders/load-domain-permission-by-domain-id.js:61 msgid "Permission check error. Unable to request domain information." msgstr "Erreur de vérification des permissions. Impossible de demander des informations sur le domaine." #: src/organization/queries/find-organization-by-slug.js:50 -#: src/organization/queries/find-organization-by-slug.js:55 +#: src/organization/queries/find-organization-by-slug.js:52 msgid "Permission Denied: Could not retrieve specified organization." msgstr "Permission refusée : Impossible de récupérer l'organisation spécifiée." @@ -388,11 +392,11 @@ msgstr "Permission refusée : Veuillez contacter le propriétaire de l'org pour msgid "Permission Denied: Please contact organization admin for help with archiving domains." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur l'archivage des domaines." -#: src/tags/mutations/create-tag.js:136 +#: src/tags/mutations/create-tag.js:131 msgid "Permission Denied: Please contact organization admin for help with creating tag." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la création d'un tag." -#: src/domain/mutations/remove-domain.js:95 +#: src/domain/mutations/remove-domain.js:96 msgid "Permission Denied: Please contact organization admin for help with removing domain." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide afin de supprimer le domaine." @@ -400,26 +404,26 @@ msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisat msgid "Permission Denied: Please contact organization admin for help with removing domains." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la suppression des domaines." -#: src/organization/mutations/remove-organization.js:70 +#: src/organization/mutations/remove-organization.js:67 msgid "Permission Denied: Please contact organization admin for help with removing organization." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide afin de supprimer l'organisation." -#: src/affiliation/mutations/remove-user-from-org.js:127 -#: src/affiliation/mutations/remove-user-from-org.js:139 +#: src/affiliation/mutations/remove-user-from-org.js:128 +#: src/affiliation/mutations/remove-user-from-org.js:140 msgid "Permission Denied: Please contact organization admin for help with removing users." msgstr "Autorisation refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la suppression des utilisateurs." -#: src/domain/mutations/update-domains-by-domain-ids.js:80 -#: src/domain/mutations/update-domains-by-filters.js:88 +#: src/domain/mutations/update-domains-by-domain-ids.js:81 +#: src/domain/mutations/update-domains-by-filters.js:89 msgid "Permission Denied: Please contact organization admin for help with updating domains." msgstr "Autorisation refusée : veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide concernant la mise à jour des domaines." -#: src/organization/mutations/update-organization.js:155 +#: src/organization/mutations/update-organization.js:152 msgid "Permission Denied: Please contact organization admin for help with updating organization." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la suppression des utilisateurs." -#: src/tags/mutations/update-tag.js:146 -#: src/tags/mutations/update-tag.js:157 +#: src/tags/mutations/update-tag.js:125 +#: src/tags/mutations/update-tag.js:136 msgid "Permission Denied: Please contact organization admin for help with updating tag." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la mise à jour de la balise." @@ -429,17 +433,15 @@ msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisat #~ msgid "Permission Denied: Please contact organization admin for help with updating user roles." #~ msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la mise à jour des rôles des utilisateurs." -#: src/affiliation/mutations/invite-user-to-org.js:102 +#: src/affiliation/mutations/invite-user-to-org.js:99 msgid "Permission Denied: Please contact organization admin for help with user invitations." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide concernant les invitations d'utilisateurs." -#: src/affiliation/mutations/update-user-role.js:110 -#: src/affiliation/mutations/update-user-role.js:161 -#: src/affiliation/mutations/update-user-role.js:173 +#: src/affiliation/mutations/update-user-role.js:112 msgid "Permission Denied: Please contact organization admin for help with user role changes." msgstr "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur les changements de rôle des utilisateurs." -#: src/domain/mutations/create-domain.js:121 +#: src/domain/mutations/create-domain.js:130 msgid "Permission Denied: Please contact organization user for help with creating domain." msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide sur la création du domaine." @@ -452,29 +454,29 @@ msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation #~ msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide afin de récupérer les étiquettes." #: src/domain/queries/find-domain-by-domain.js:51 -#: src/organization/objects/organization.js:198 +#: src/organization/objects/organization.js:195 msgid "Permission Denied: Please contact organization user for help with retrieving this domain." msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide pour récupérer ce domaine." #: src/domain/mutations/request-discovery.js:98 -#: src/domain/mutations/request-scan.js:65 +#: src/domain/mutations/request-scan.js:66 msgid "Permission Denied: Please contact organization user for help with scanning this domain." msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide sur l'analyse de ce domaine." -#: src/domain/mutations/update-domain.js:137 +#: src/domain/mutations/update-domain.js:151 msgid "Permission Denied: Please contact organization user for help with updating this domain." msgstr "Autorisation refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide sur la mise à jour de ce domaine." -#: src/organization/mutations/archive-organization.js:69 +#: src/organization/mutations/archive-organization.js:66 msgid "Permission Denied: Please contact super admin for help with archiving organization." msgstr "Permission refusée : Veuillez contacter le super administrateur pour obtenir de l'aide sur l'organisation de l'archivage." -#: src/domain/mutations/remove-domain.js:108 +#: src/domain/mutations/remove-domain.js:109 #: src/domain/mutations/remove-organizations-domains.js:106 msgid "Permission Denied: Please contact super admin for help with removing domain." msgstr "Permission refusée : Veuillez contacter l'utilisateur de l'organisation pour obtenir de l'aide sur la mise à jour de ce domaine." -#: src/organization/mutations/remove-organization.js:83 +#: src/organization/mutations/remove-organization.js:80 msgid "Permission Denied: Please contact super admin for help with removing organization." msgstr "Permission refusée : Veuillez contacter le super administrateur pour qu'il vous aide à supprimer l'organisation." @@ -482,18 +484,26 @@ msgstr "Permission refusée : Veuillez contacter le super administrateur pour qu #~ msgid "Permission Denied: Please contact super admin for help with scanning this domain." #~ msgstr "Permission refusée : Veuillez contacter le super administrateur pour obtenir de l'aide sur l'analyse de ce domaine." -#: src/tags/mutations/update-tag.js:168 +#: src/tags/mutations/update-tag.js:147 msgid "Permission Denied: Please contact super admin for help with updating tag." msgstr "Autorisation refusée : veuillez contacter l'administrateur principal pour obtenir de l'aide concernant la mise à jour de la balise." -#: src/organization/mutations/verify-organization.js:68 +#: src/affiliation/mutations/invite-user-to-org.js:112 +msgid "Permission Denied: Please contact super admin for help with user invitations." +msgstr "Accès refusé : veuillez contacter l'administrateur principal pour obtenir de l'aide concernant les invitations d'utilisateurs." + +#: src/affiliation/mutations/update-user-role.js:167 +msgid "Permission Denied: Please contact super admin for help with user role changes." +msgstr "Accès refusé : veuillez contacter l'administrateur principal pour obtenir de l'aide concernant la modification des rôles d'utilisateur." + +#: src/organization/mutations/verify-organization.js:65 msgid "Permission Denied: Please contact super admin for help with verifying this organization." msgstr "Permission refusée : Veuillez contacter le super administrateur pour qu'il vous aide à vérifier cette organisation." -#: src/auth/check-user-is-admin-for-user.js:20 -#: src/auth/check-user-is-admin-for-user.js:30 -#: src/auth/check-user-is-admin-for-user.js:63 -#: src/auth/check-user-is-admin-for-user.js:73 +#: src/auth/checks/check-user-is-admin-for-user.js:20 +#: src/auth/checks/check-user-is-admin-for-user.js:30 +#: src/auth/checks/check-user-is-admin-for-user.js:63 +#: src/auth/checks/check-user-is-admin-for-user.js:73 msgid "Permission error, not an admin for this user." msgstr "Erreur de permission, pas d'administrateur pour cet utilisateur." @@ -501,7 +511,7 @@ msgstr "Erreur de permission, pas d'administrateur pour cet utilisateur." msgid "Permission error: Unable to close other user's account." msgstr "Erreur de permission: Impossible de fermer le compte d'un autre utilisateur." -#: src/auth/super-admin-required.js:11 +#: src/auth/guards/super-admin-required.js:11 msgid "Permissions error. You do not have sufficient permissions to access this data." msgstr "Erreur de permissions. Vous n'avez pas les autorisations suffisantes pour accéder à ces données." @@ -563,8 +573,8 @@ msgstr "La demande d'enregistrements `{amount}` sur la connexion `DkimFailureTab msgid "Requesting `{amount}` records on the `DmarcSummaries` connection exceeds the `{argSet}` limit of 100 records." msgstr "La demande d'enregistrements `{amount}` sur la connexion `DmarcSummaries` dépasse la limite `{argSet}` de 100 enregistrements." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:163 -#: src/domain/loaders/load-domain-connections-by-user-id.js:190 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:164 +#: src/domain/loaders/load-domain-connections-by-user-id.js:191 msgid "Requesting `{amount}` records on the `Domain` connection exceeds the `{argSet}` limit of 100 records." msgstr "La demande d'enregistrements `{amount}` sur la connexion `Domain` dépasse la limite `{argSet}` de 100 enregistrements." @@ -618,7 +628,7 @@ msgstr "Ajouté avec succès le(s) domaine(s) {domainCount} à {0}." #~ msgstr "Ajouté avec succès les domaines {domainCount} à {0}." #. placeholder {0}: organization.slug -#: src/organization/mutations/archive-organization.js:195 +#: src/organization/mutations/archive-organization.js:100 msgid "Successfully archived organization: {0}." msgstr "Organisation archivée avec succès : {0}." @@ -627,7 +637,7 @@ msgstr "Organisation archivée avec succès : {0}." msgid "Successfully closed account." msgstr "Le compte a été fermé avec succès." -#: src/domain/mutations/request-scan.js:174 +#: src/domain/mutations/request-scan.js:175 msgid "Successfully dispatched one time scan." msgstr "Un seul balayage a été effectué avec succès." @@ -643,7 +653,7 @@ msgstr "L'analyse de découverte du sous-domaine a été effectuée avec succès msgid "Successfully email verified account." msgstr "Envoi d'un courriel à un compte vérifié." -#: src/affiliation/mutations/invite-user-to-org.js:288 +#: src/affiliation/mutations/invite-user-to-org.js:282 msgid "Successfully invited user to organization, and sent notification email." msgstr "L'utilisateur a été invité avec succès à l'organisation et l'email de notification a été envoyé." @@ -663,7 +673,7 @@ msgstr "Supprimé avec succès le(s) domaine(s) {domainCount} de {0}." #. placeholder {0}: domain.domain #. placeholder {1}: org.slug -#: src/domain/mutations/remove-domain.js:372 +#: src/domain/mutations/remove-domain.js:373 msgid "Successfully removed domain: {0} from {1}." msgstr "A réussi à supprimer le domaine : {0} de {1}." @@ -673,19 +683,19 @@ msgid "Successfully removed domain: {0} from favourites." msgstr "A réussi à supprimer le domaine : {0} des favoris." #. placeholder {0}: organization.slug -#: src/organization/mutations/remove-organization.js:418 +#: src/organization/mutations/remove-organization.js:107 msgid "Successfully removed organization: {0}." msgstr "A réussi à supprimer l'organisation : {0}." -#: src/affiliation/mutations/remove-user-from-org.js:200 +#: src/affiliation/mutations/remove-user-from-org.js:201 msgid "Successfully removed user from organization." msgstr "L'utilisateur a été retiré de l'organisation avec succès." -#: src/affiliation/mutations/request-org-affiliation.js:247 +#: src/affiliation/mutations/request-org-affiliation.js:231 msgid "Successfully requested invite to organization, and sent notification email." msgstr "La demande d'invitation à l'organisation a été effectuée avec succès et un courriel de notification a été envoyé." -#: src/affiliation/mutations/invite-user-to-org.js:176 +#: src/affiliation/mutations/invite-user-to-org.js:170 msgid "Successfully sent invitation to service, and organization email." msgstr "Envoi réussi de l'invitation au service, et de l'email de l'organisation." @@ -701,13 +711,13 @@ msgstr "A réussi à transférer la propriété de org: {0} à l'utilisateur: {1 #. placeholder {0}: org.slug #. placeholder {1}: tags.join(', ') -#: src/domain/mutations/update-domains-by-domain-ids.js:178 -#: src/domain/mutations/update-domains-by-filters.js:309 +#: src/domain/mutations/update-domains-by-domain-ids.js:179 +#: src/domain/mutations/update-domains-by-filters.js:310 msgid "Successfully updated {domainCount} domain(s) in {0} with {1}." msgstr "Mise à jour réussie de {domainCount} domaine(s) dans {0} avec {1}." #. placeholder {0}: currentOrg.slug -#: src/organization/mutations/verify-organization.js:138 +#: src/organization/mutations/verify-organization.js:90 msgid "Successfully verified organization: {0}." msgstr "Envoi réussi de l'invitation au service, et de l'email de l'organisation." @@ -719,9 +729,9 @@ msgstr "Le numéro de téléphone a été vérifié avec succès, et la méthode #~ msgid "Tag label already in use, please choose another and try again." #~ msgstr "L'étiquette est déjà utilisée, veuillez en choisir une autre et réessayer." -#: src/tags/mutations/create-tag.js:96 -#: src/tags/mutations/create-tag.js:153 -#: src/tags/mutations/update-tag.js:182 +#: src/tags/mutations/create-tag.js:94 +#: src/tags/mutations/create-tag.js:148 +#: src/tags/mutations/update-tag.js:161 msgid "Tag label already in use. Please try again with a different label." msgstr "L'étiquette est déjà utilisée. Veuillez réessayer avec une autre étiquette." @@ -754,15 +764,14 @@ msgstr "Impossible de quitter l'organisation. Veuillez réessayer." msgid "Unable to add domains in unknown organization." msgstr "Impossible d'ajouter des domaines dans une organisation inconnue." -#: src/organization/mutations/archive-organization.js:103 -#: src/organization/mutations/archive-organization.js:114 -#: src/organization/mutations/archive-organization.js:133 -#: src/organization/mutations/archive-organization.js:151 -#: src/organization/mutations/archive-organization.js:161 +#: src/organization/data-source.js:179 +#: src/organization/data-source.js:194 +#: src/organization/data-source.js:209 +#: src/organization/data-source.js:217 msgid "Unable to archive organization. Please try again." msgstr "Impossible d'archiver l'organisation. Veuillez réessayer." -#: src/organization/mutations/archive-organization.js:55 +#: src/organization/mutations/archive-organization.js:52 msgid "Unable to archive unknown organization." msgstr "Impossible d'archiver une organisation inconnue." @@ -773,10 +782,12 @@ msgstr "Impossible d'archiver une organisation inconnue." msgid "Unable to authenticate. Please try again." msgstr "Impossible de s'authentifier. Veuillez réessayer." -#: src/auth/check-permission.js:26 -#: src/auth/check-permission.js:64 -#: src/auth/check-super-admin.js:20 -#: src/auth/check-super-admin.js:30 +#: src/auth/checks/check-permission.js:26 +#: src/auth/checks/check-permission.js:64 +#: src/auth/checks/check-super-admin.js:20 +#: src/auth/checks/check-super-admin.js:30 +#: src/auth/loaders/load-permission-by-org-id.js:27 +#: src/auth/loaders/load-permission-by-org-id.js:73 msgid "Unable to check permission. Please try again." msgstr "Impossible de vérifier l'autorisation. Veuillez réessayer." @@ -798,20 +809,20 @@ msgstr "Impossible de fermer le compte. Veuillez réessayer." msgid "Unable to confirm completion of the tour. Please try again." msgstr "Impossible de confirmer l'achèvement de la visite. Veuillez réessayer." -#: src/domain/mutations/create-domain.js:107 +#: src/domain/mutations/create-domain.js:116 msgid "Unable to create domain in unknown organization." msgstr "Impossible de créer un domaine dans une organisation inconnue." -#: src/domain/mutations/create-domain.js:178 +#: src/domain/mutations/create-domain.js:199 msgid "Unable to create domain, organization has already claimed it." msgstr "Impossible de créer le domaine, l'organisation l'a déjà réclamé." -#: src/domain/mutations/create-domain.js:160 -#: src/domain/mutations/create-domain.js:168 -#: src/domain/mutations/create-domain.js:200 -#: src/domain/mutations/create-domain.js:209 -#: src/domain/mutations/create-domain.js:229 -#: src/domain/mutations/create-domain.js:237 +#: src/domain/mutations/create-domain.js:181 +#: src/domain/mutations/create-domain.js:189 +#: src/domain/mutations/create-domain.js:221 +#: src/domain/mutations/create-domain.js:230 +#: src/domain/mutations/create-domain.js:250 +#: src/domain/mutations/create-domain.js:258 msgid "Unable to create domain. Please try again." msgstr "Impossible de créer un domaine. Veuillez réessayer." @@ -819,22 +830,22 @@ msgstr "Impossible de créer un domaine. Veuillez réessayer." msgid "Unable to create domains. Please try again." msgstr "Impossible de créer des domaines. Veuillez réessayer." -#: src/organization/mutations/create-organization.js:185 -#: src/organization/mutations/create-organization.js:206 -#: src/organization/mutations/create-organization.js:216 +#: src/organization/data-source.js:58 +#: src/organization/data-source.js:76 +#: src/organization/data-source.js:84 msgid "Unable to create organization. Please try again." msgstr "Impossible de créer une organisation. Veuillez réessayer." -#: src/tags/mutations/create-tag.js:124 +#: src/tags/mutations/create-tag.js:119 msgid "Unable to create tag in unknown organization." msgstr "Impossible de créer une étiquette dans une organisation inconnue." -#: src/tags/mutations/create-tag.js:113 +#: src/tags/mutations/create-tag.js:108 msgid "Unable to create tag, tagId already in use." msgstr "Impossible de créer une balise, tagId déjà utilisé." -#: src/tags/mutations/create-tag.js:172 -#: src/tags/mutations/create-tag.js:180 +#: src/tags/data-source.js:58 +#: src/tags/data-source.js:65 msgid "Unable to create tag. Please try again." msgstr "Impossible de créer une balise. Veuillez réessayer." @@ -853,8 +864,7 @@ msgstr "Impossible de rejeter le message. Veuillez réessayer." #~ msgid "Unable to dispatch one time scan. Please try again." #~ msgstr "Impossible d'envoyer un scan unique. Veuillez réessayer." -#: src/organization/objects/organization.js:275 -#: src/organization/objects/organization.js:285 +#: src/organization/objects/organization.js:265 msgid "Unable to export organization. Please try again." msgstr "Impossible d'exporter l'organisation. Veuillez réessayer." @@ -973,26 +983,25 @@ msgstr "Impossible de trouver une ou plusieurs organisations vérifiées. Veuill msgid "Unable to ignore CVE. Please try again." msgstr "Impossible d'ignorer le CVE. Veuillez réessayer." -#: src/affiliation/mutations/invite-user-to-org.js:120 -#: src/affiliation/mutations/invite-user-to-org.js:130 -#: src/affiliation/mutations/invite-user-to-org.js:196 +#: src/affiliation/mutations/invite-user-to-org.js:124 +#: src/affiliation/mutations/invite-user-to-org.js:190 msgid "Unable to invite user to organization. Please try again." msgstr "Impossible d'inviter un utilisateur dans une organisation. Veuillez réessayer." -#: src/affiliation/mutations/invite-user-to-org.js:208 +#: src/affiliation/mutations/invite-user-to-org.js:202 msgid "Unable to invite user to organization. User is already affiliated with organization." msgstr "Impossible d'inviter un utilisateur dans une organisation. L'utilisateur est déjà affilié à l'organisation." -#: src/affiliation/mutations/invite-user-to-org.js:83 +#: src/affiliation/mutations/invite-user-to-org.js:84 msgid "Unable to invite user to unknown organization." msgstr "Impossible d'inviter un utilisateur à une organisation inconnue." -#: src/affiliation/mutations/invite-user-to-org.js:238 -#: src/affiliation/mutations/invite-user-to-org.js:259 +#: src/affiliation/mutations/invite-user-to-org.js:232 +#: src/affiliation/mutations/invite-user-to-org.js:253 msgid "Unable to invite user. Please try again." msgstr "Impossible d'inviter un utilisateur. Veuillez réessayer." -#: src/affiliation/mutations/invite-user-to-org.js:69 +#: src/affiliation/mutations/invite-user-to-org.js:70 msgid "Unable to invite yourself to an org." msgstr "Impossible de s'inviter à un org." @@ -1010,7 +1019,7 @@ msgstr "Impossible de quitter une organisation non définie." msgid "Unable to load additional findings. Please try again." msgstr "Impossible de charger des résultats supplémentaires. Veuillez réessayer." -#: src/auth/check-user-belongs-to-org.js:20 +#: src/auth/checks/check-user-belongs-to-org.js:20 msgid "Unable to load affiliation information. Please try again." msgstr "Impossible de charger les informations d'affiliation. Veuillez réessayer." @@ -1055,8 +1064,8 @@ msgstr "Impossible de charger le(s) tag(s) d'orientation DKIM. Veuillez réessay #~ msgstr "Impossible de charger le(s) scan(s) DKIM. Veuillez réessayer." #: src/summaries/queries/dkim-summary.js:12 -msgid "Unable to load DKIM summary. Please try again." -msgstr "Impossible de charger le résumé DKIM. Veuillez réessayer." +#~ msgid "Unable to load DKIM summary. Please try again." +#~ msgstr "Impossible de charger le résumé DKIM. Veuillez réessayer." #: src/dmarc-summaries/loaders/load-dmarc-failure-connections-by-sum-id.js:13 #: src/dmarc-summaries/loaders/load-dmarc-failure-connections-by-sum-id.js:141 @@ -1070,8 +1079,8 @@ msgid "Unable to load DMARC guidance tag(s). Please try again." msgstr "Impossible de charger le(s) tag(s) d'orientation DMARC. Veuillez réessayer." #: src/summaries/queries/dmarc-phase-summary.js:12 -msgid "Unable to load DMARC phase summary. Please try again." -msgstr "Impossible de charger le résumé DMARC. Veuillez réessayer." +#~ msgid "Unable to load DMARC phase summary. Please try again." +#~ msgstr "Impossible de charger le résumé DMARC. Veuillez réessayer." #: src/email-scan/loaders/load-dmarc-connections-by-domain-id.js:319 #: src/email-scan/loaders/load-dmarc-connections-by-domain-id.js:331 @@ -1088,13 +1097,11 @@ msgid "Unable to load DMARC summary data. Please try again." msgstr "Impossible de charger les données de synthèse DMARC. Veuillez réessayer." #: src/summaries/queries/dmarc-summary.js:12 -msgid "Unable to load DMARC summary. Please try again." -msgstr "Impossible de charger le résumé DMARC. Veuillez réessayer." +#~ msgid "Unable to load DMARC summary. Please try again." +#~ msgstr "Impossible de charger le résumé DMARC. Veuillez réessayer." #: src/dns-scan/loaders/load-dns-connections-by-domain-id.js:154 #: src/dns-scan/loaders/load-dns-connections-by-domain-id.js:164 -#: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:156 -#: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:166 msgid "Unable to load DNS scan(s). Please try again." msgstr "Impossible de charger le(s) scan(s) DNS. Veuillez réessayer." @@ -1110,9 +1117,9 @@ msgstr "Impossible de charger le(s) sélecteur(s) de domaine. Veuillez réessaye msgid "Unable to load domain. Please try again." msgstr "Impossible de charger le domaine. Veuillez réessayer." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:523 -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:533 -#: src/domain/loaders/load-domain-connections-by-user-id.js:575 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:402 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:412 +#: src/domain/loaders/load-domain-connections-by-user-id.js:469 #: src/user/loaders/load-my-tracker-by-user-id.js:33 msgid "Unable to load domain(s). Please try again." msgstr "Impossible de charger le(s) domaine(s). Veuillez réessayer." @@ -1140,8 +1147,8 @@ msgstr "Impossible de charger la ou les balises d'orientation HTTPS. Veuillez r #~ msgstr "Impossible de charger le(s) scan(s) HTTPS. Veuillez réessayer." #: src/summaries/queries/https-summary.js:13 -msgid "Unable to load HTTPS summary. Please try again." -msgstr "Impossible de charger le résumé HTTPS. Veuillez réessayer." +#~ msgid "Unable to load HTTPS summary. Please try again." +#~ msgstr "Impossible de charger le résumé HTTPS. Veuillez réessayer." #: src/audit-logs/loaders/load-audit-log-by-key.js:19 #: src/audit-logs/loaders/load-audit-log-by-key.js:31 @@ -1153,20 +1160,32 @@ msgid "Unable to load log(s). Please try again." msgstr "Impossible de charger le(s) journal(s). Veuillez réessayer." #: src/summaries/queries/mail-summary.js:12 -msgid "Unable to load mail summary. Please try again." -msgstr "Impossible de charger le résumé du courrier. Veuillez réessayer." +#~ msgid "Unable to load mail summary. Please try again." +#~ msgstr "Impossible de charger le résumé du courrier. Veuillez réessayer." #: src/additional-findings/loaders/load-top-25-reports.js:29 #: src/organization/loaders/load-all-organization-domain-statuses.js:164 -#: src/organization/loaders/load-organization-domain-statuses.js:166 +#: src/organization/loaders/load-organization-domain-statuses.js:172 msgid "Unable to load organization domain statuses. Please try again." msgstr "Impossible de charger les statuts des domaines d'organisation. Veuillez réessayer." +#: src/organization/loaders/load-organization-names-by-id.js:19 +#: src/organization/loaders/load-organization-names-by-id.js:29 +msgid "Unable to load organization names. Please try again." +msgstr "Impossible de charger les noms des organisations. Veuillez réessayer." + #: src/organization/loaders/load-organization-summaries-by-period.js:56 #: src/organization/loaders/load-organization-summaries-by-period.js:66 msgid "Unable to load organization summary data. Please try again." msgstr "Impossible de charger les données de synthèse de l'organisation. Veuillez réessayer." +#: src/organization/data-source.js:117 +#: src/organization/data-source.js:124 +#: src/organization/data-source.js:144 +#: src/organization/data-source.js:152 +msgid "Unable to load organization. Please try again." +msgstr "Impossible de charger l'organisation. Veuillez réessayer." + #: src/organization/loaders/load-organization-by-key.js:31 #: src/organization/loaders/load-organization-by-key.js:41 #: src/organization/loaders/load-organization-by-slug.js:34 @@ -1178,8 +1197,10 @@ msgstr "Impossible de charger les données de synthèse de l'organisation. Veuil msgid "Unable to load organization(s). Please try again." msgstr "Impossible de charger l'organisation (s). Veuillez réessayer." -#: src/auth/check-org-owner.js:19 -#: src/auth/check-org-owner.js:27 +#: src/auth/checks/check-org-owner.js:19 +#: src/auth/checks/check-org-owner.js:27 +#: src/auth/loaders/load-org-owner-by-org-id.js:23 +#: src/auth/loaders/load-org-owner-by-org-id.js:33 msgid "Unable to load owner information. Please try again." msgstr "Impossible de charger les informations sur le propriétaire. Veuillez réessayer." @@ -1200,8 +1221,8 @@ msgstr "Impossible de charger le(s) tag(s) d'orientation SPF. Veuillez réessaye #~ msgstr "Impossible de charger le(s) scan(s) SPF. Veuillez réessayer." #: src/summaries/queries/spf-summary.js:12 -msgid "Unable to load SPF summary. Please try again." -msgstr "Impossible de charger le résumé SPF. Veuillez réessayer." +#~ msgid "Unable to load SPF summary. Please try again." +#~ msgstr "Impossible de charger le résumé SPF. Veuillez réessayer." #: src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js:260 #: src/guidance-tag/loaders/load-ssl-guidance-tags-connections.js:272 @@ -1214,13 +1235,13 @@ msgstr "Impossible de charger le(s) tag(s) d'orientation SSL. Veuillez réessaye #~ msgstr "Impossible de charger le(s) scan(s) SSL. Veuillez réessayer." #: src/summaries/queries/ssl-summary.js:12 -msgid "Unable to load SSL summary. Please try again." -msgstr "Impossible de charger le résumé SSL. Veuillez réessayer." +#~ msgid "Unable to load SSL summary. Please try again." +#~ msgstr "Impossible de charger le résumé SSL. Veuillez réessayer." #: src/summaries/loaders/load-chart-summary-by-key.js:17 #: src/summaries/loaders/load-chart-summary-by-key.js:25 -msgid "Unable to load summary. Please try again." -msgstr "Impossible de charger le résumé. Veuillez réessayer." +#~ msgid "Unable to load summary. Please try again." +#~ msgstr "Impossible de charger le résumé. Veuillez réessayer." #: src/tags/loaders/load-all-tags.js:36 #: src/tags/loaders/load-all-tags.js:44 @@ -1266,8 +1287,8 @@ msgid "Unable to load verified rua domains. Please try again." msgstr "Impossible de charger les domaines rua vérifiés. Veuillez réessayer." #: src/summaries/queries/web-connections-summary.js:12 -msgid "Unable to load web connections summary. Please try again." -msgstr "Impossible de charger le résumé des connexions web. Veuillez réessayer." +#~ msgid "Unable to load web connections summary. Please try again." +#~ msgstr "Impossible de charger le résumé des connexions web. Veuillez réessayer." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:169 #: src/web-scan/loaders/load-web-connections-by-domain-id.js:179 @@ -1278,15 +1299,15 @@ msgid "Unable to load web scan(s). Please try again." msgstr "Impossible de charger le(s) scan(s) web. Veuillez réessayer." #: src/summaries/queries/web-summary.js:13 -msgid "Unable to load web summary. Please try again." -msgstr "Impossible de charger le résumé web. Veuillez réessayer." +#~ msgid "Unable to load web summary. Please try again." +#~ msgstr "Impossible de charger le résumé web. Veuillez réessayer." #: src/affiliation/loaders/load-affiliation-connections-by-org-id.js:293 #: src/affiliation/loaders/load-affiliation-connections-by-user-id.js:437 msgid "Unable to query affiliation(s). Please try again." msgstr "Impossible de demander l'affiliation (s). Veuillez réessayer." -#: src/domain/loaders/load-domain-connections-by-user-id.js:565 +#: src/domain/loaders/load-domain-connections-by-user-id.js:459 #: src/user/loaders/load-my-tracker-by-user-id.js:23 msgid "Unable to query domain(s). Please try again." msgstr "Impossible d'interroger le(s) domaine(s). Veuillez réessayer." @@ -1309,29 +1330,29 @@ msgstr "Impossible d'interroger le(s) utilisateur(s). Veuillez réessayer." msgid "Unable to refresh tokens, please sign in." msgstr "Impossible de rafraîchir les jetons, veuillez vous connecter." -#: src/affiliation/mutations/remove-user-from-org.js:105 +#: src/affiliation/mutations/remove-user-from-org.js:106 msgid "Unable to remove a user that already does not belong to this organization." msgstr "Impossible de supprimer un utilisateur qui n'appartient déjà plus à cette organisation." -#: src/domain/mutations/remove-domain.js:81 +#: src/domain/mutations/remove-domain.js:82 msgid "Unable to remove domain from unknown organization." msgstr "Impossible de supprimer le domaine d'une organisation inconnue." -#: src/domain/mutations/remove-domain.js:137 +#: src/domain/mutations/remove-domain.js:138 msgid "Unable to remove domain. Domain is not part of organization." msgstr "Impossible de supprimer le domaine. Le domaine ne fait pas partie de l'organisation." -#: src/domain/mutations/remove-domain.js:124 -#: src/domain/mutations/remove-domain.js:153 -#: src/domain/mutations/remove-domain.js:187 -#: src/domain/mutations/remove-domain.js:207 -#: src/domain/mutations/remove-domain.js:236 -#: src/domain/mutations/remove-domain.js:255 -#: src/domain/mutations/remove-domain.js:273 -#: src/domain/mutations/remove-domain.js:290 -#: src/domain/mutations/remove-domain.js:308 -#: src/domain/mutations/remove-domain.js:332 -#: src/domain/mutations/remove-domain.js:344 +#: src/domain/mutations/remove-domain.js:125 +#: src/domain/mutations/remove-domain.js:154 +#: src/domain/mutations/remove-domain.js:188 +#: src/domain/mutations/remove-domain.js:208 +#: src/domain/mutations/remove-domain.js:237 +#: src/domain/mutations/remove-domain.js:256 +#: src/domain/mutations/remove-domain.js:274 +#: src/domain/mutations/remove-domain.js:291 +#: src/domain/mutations/remove-domain.js:309 +#: src/domain/mutations/remove-domain.js:333 +#: src/domain/mutations/remove-domain.js:345 msgid "Unable to remove domain. Please try again." msgstr "Impossible de supprimer le domaine. Veuillez réessayer." @@ -1339,19 +1360,17 @@ msgstr "Impossible de supprimer le domaine. Veuillez réessayer." msgid "Unable to remove domains from unknown organization." msgstr "Impossible de supprimer les domaines d'une organisation inconnue." -#: src/organization/mutations/remove-organization.js:103 -#: src/organization/mutations/remove-organization.js:114 -#: src/organization/mutations/remove-organization.js:145 -#: src/organization/mutations/remove-organization.js:161 -#: src/organization/mutations/remove-organization.js:192 -#: src/organization/mutations/remove-organization.js:203 -#: src/organization/mutations/remove-organization.js:230 -#: src/organization/mutations/remove-organization.js:249 -#: src/organization/mutations/remove-organization.js:267 -#: src/organization/mutations/remove-organization.js:284 -#: src/organization/mutations/remove-organization.js:317 -#: src/organization/mutations/remove-organization.js:382 -#: src/organization/mutations/remove-organization.js:392 +#: src/organization/data-source.js:278 +#: src/organization/data-source.js:307 +#: src/organization/data-source.js:321 +#: src/organization/data-source.js:350 +#: src/organization/data-source.js:374 +#: src/organization/data-source.js:390 +#: src/organization/data-source.js:405 +#: src/organization/data-source.js:419 +#: src/organization/data-source.js:448 +#: src/organization/data-source.js:490 +#: src/organization/data-source.js:498 msgid "Unable to remove organization. Please try again." msgstr "Impossible de supprimer l'organisation. Veuillez réessayer." @@ -1360,15 +1379,15 @@ msgstr "Impossible de supprimer l'organisation. Veuillez réessayer." msgid "Unable to remove phone number. Please try again." msgstr "Impossible de supprimer le numéro de téléphone. Veuillez réessayer." -#: src/domain/mutations/remove-domain.js:66 +#: src/domain/mutations/remove-domain.js:67 msgid "Unable to remove unknown domain." msgstr "Impossible de supprimer un domaine inconnu." -#: src/organization/mutations/remove-organization.js:55 +#: src/organization/mutations/remove-organization.js:52 msgid "Unable to remove unknown organization." msgstr "Impossible de supprimer une organisation inconnue." -#: src/affiliation/mutations/remove-user-from-org.js:78 +#: src/affiliation/mutations/remove-user-from-org.js:79 msgid "Unable to remove unknown user from organization." msgstr "Impossible de supprimer un utilisateur inconnu de l'organisation." @@ -1376,26 +1395,26 @@ msgstr "Impossible de supprimer un utilisateur inconnu de l'organisation." #~ msgid "Unable to remove user from organization." #~ msgstr "Impossible de supprimer un utilisateur de l'organisation." -#: src/affiliation/mutations/remove-user-from-org.js:95 -#: src/affiliation/mutations/remove-user-from-org.js:116 -#: src/affiliation/mutations/remove-user-from-org.js:163 -#: src/affiliation/mutations/remove-user-from-org.js:173 +#: src/affiliation/mutations/remove-user-from-org.js:96 +#: src/affiliation/mutations/remove-user-from-org.js:117 +#: src/affiliation/mutations/remove-user-from-org.js:164 +#: src/affiliation/mutations/remove-user-from-org.js:174 msgid "Unable to remove user from this organization. Please try again." msgstr "Impossible de supprimer l'utilisateur de cette organisation. Veuillez réessayer." -#: src/affiliation/mutations/remove-user-from-org.js:62 +#: src/affiliation/mutations/remove-user-from-org.js:63 msgid "Unable to remove user from unknown organization." msgstr "Impossible de supprimer un utilisateur d'une organisation inconnue." -#: src/domain/mutations/request-scan.js:119 +#: src/domain/mutations/request-scan.js:120 msgid "Unable to request a one time scan on a domain that already has a pending scan." msgstr "Impossible de demander une analyse unique sur un domaine qui a déjà une analyse en cours." -#: src/domain/mutations/request-scan.js:54 +#: src/domain/mutations/request-scan.js:55 msgid "Unable to request a one time scan on an unknown domain." msgstr "Impossible de demander un scan unique sur un domaine inconnu." -#: src/domain/mutations/request-scan.js:127 +#: src/domain/mutations/request-scan.js:128 msgid "Unable to request a one time scan. Please try again." msgstr "Impossible de demander une analyse unique. Veuillez réessayer." @@ -1423,9 +1442,8 @@ msgstr "Impossible de demander une invitation à une organisation inconnue." #: src/affiliation/mutations/request-org-affiliation.js:124 #: src/affiliation/mutations/request-org-affiliation.js:141 #: src/affiliation/mutations/request-org-affiliation.js:152 -#: src/affiliation/mutations/request-org-affiliation.js:173 -#: src/affiliation/mutations/request-org-affiliation.js:183 -#: src/affiliation/mutations/request-org-affiliation.js:214 +#: src/affiliation/mutations/request-org-affiliation.js:167 +#: src/affiliation/mutations/request-org-affiliation.js:198 msgid "Unable to request invite. Please try again." msgstr "Impossible de demander une invitation. Veuillez réessayer." @@ -1439,8 +1457,8 @@ msgstr "Impossible de demander une invitation. Veuillez réessayer." msgid "Unable to reset password. Please try again." msgstr "Impossible de réinitialiser le mot de passe. Veuillez réessayer." -#: src/domain/objects/domain.js:324 -#: src/domain/objects/domain.js:359 +#: src/domain/objects/domain.js:274 +#: src/domain/objects/domain.js:309 msgid "Unable to retrieve DMARC report information for: {domain}" msgstr "Impossible de récupérer les informations du rapport DMARC pour : {domain}" @@ -1470,6 +1488,10 @@ msgstr "Impossible d'envoyer l'email de demande d'invitation à l'org. Veuillez msgid "Unable to send password reset email. Please try again." msgstr "Impossible d'envoyer l'email de réinitialisation du mot de passe. Veuillez réessayer." +#: src/notify/notify-send-role-change-email.js:21 +#~ msgid "Unable to send role update email. Please try again." +#~ msgstr "Impossible d'envoyer l'e-mail de mise à jour du rôle. Veuillez réessayer." + #: src/notify/notify-send-tfa-text-msg.js:30 #~ msgid "Unable to send two factor authentication message. Please try again." #~ msgstr "Impossible d'envoyer le message d'authentification à deux facteurs. Veuillez réessayer." @@ -1559,40 +1581,36 @@ msgstr "Impossible de défavoriser le domaine. Veuillez réessayer." msgid "Unable to unfavourite unknown domain." msgstr "Impossible de défavoriser un domaine inconnu." -#: src/domain/mutations/update-domain.js:236 +#: src/domain/mutations/update-domain.js:261 msgid "Unable to update domain edge. Please try again." msgstr "Impossible de mettre à jour le bord du domaine. Veuillez réessayer." -#: src/domain/mutations/update-domain.js:123 +#: src/domain/mutations/update-domain.js:137 msgid "Unable to update domain in an unknown org." msgstr "Impossible de mettre à jour le domaine dans un org inconnu." -#: src/domain/mutations/update-domain.js:164 +#: src/domain/mutations/update-domain.js:178 msgid "Unable to update domain that does not belong to the given organization." msgstr "Impossible de mettre à jour un domaine qui n'appartient pas à l'organisation donnée." -#: src/domain/mutations/update-domain.js:154 -#: src/domain/mutations/update-domain.js:193 -#: src/domain/mutations/update-domain.js:247 +#: src/domain/mutations/update-domain.js:168 +#: src/domain/mutations/update-domain.js:218 +#: src/domain/mutations/update-domain.js:272 msgid "Unable to update domain. Please try again." msgstr "Impossible de mettre à jour le domaine. Veuillez réessayer." -#: src/domain/mutations/update-domains-by-domain-ids.js:67 -#: src/domain/mutations/update-domains-by-filters.js:75 +#: src/domain/mutations/update-domains-by-domain-ids.js:68 +#: src/domain/mutations/update-domains-by-filters.js:76 msgid "Unable to update domains in unknown organization." msgstr "Impossible de mettre à jour les domaines dans une organisation inconnue." -#: src/domain/mutations/update-domains-by-filters.js:228 -#: src/domain/mutations/update-domains-by-filters.js:236 -#: src/domain/mutations/update-domains-by-filters.js:243 +#: src/domain/mutations/update-domains-by-filters.js:229 +#: src/domain/mutations/update-domains-by-filters.js:237 +#: src/domain/mutations/update-domains-by-filters.js:244 msgid "Unable to update domains. Please try again." msgstr "Impossible de mettre à jour les domaines. Veuillez réessayer." -#: src/organization/mutations/update-organization.js:174 -#: src/organization/mutations/update-organization.js:200 -#: src/organization/mutations/update-organization.js:208 -#: src/organization/mutations/update-organization.js:262 -#: src/organization/mutations/update-organization.js:270 +#: src/organization/data-source.js:101 msgid "Unable to update organization. Please try again." msgstr "Impossible de mettre à jour l'organisation. Veuillez réessayer." @@ -1618,23 +1636,23 @@ msgstr "Impossible de mettre à jour le mot de passe. Veuillez réessayer." msgid "Unable to update profile. Please try again." msgstr "Impossible de mettre à jour le profil. Veuillez réessayer." -#: src/affiliation/mutations/update-user-role.js:95 +#: src/affiliation/mutations/update-user-role.js:97 msgid "Unable to update role: organization unknown." msgstr "Impossible de mettre à jour le rôle : organisation inconnue." -#: src/affiliation/mutations/update-user-role.js:138 +#: src/affiliation/mutations/update-user-role.js:140 msgid "Unable to update role: user does not belong to organization." msgstr "Impossible de mettre à jour le rôle : l'utilisateur n'appartient pas à l'organisation." -#: src/affiliation/mutations/update-user-role.js:81 +#: src/affiliation/mutations/update-user-role.js:83 msgid "Unable to update role: user unknown." msgstr "Impossible de mettre à jour le rôle : utilisateur inconnu." -#: src/tags/mutations/update-tag.js:134 +#: src/tags/mutations/update-tag.js:113 msgid "Unable to update tag in unknown organization." msgstr "Impossible de mettre à jour la balise dans une organisation inconnue." -#: src/tags/mutations/update-tag.js:124 +#: src/tags/mutations/update-tag.js:103 msgid "Unable to update tag, orgId is invalid." msgstr "Impossible de mettre à jour la balise, l'orgId est invalide." @@ -1642,33 +1660,34 @@ msgstr "Impossible de mettre à jour la balise, l'orgId est invalide." #~ msgid "Unable to update tag, tagId already in use." #~ msgstr "Impossible de mettre à jour la balise, l'identifiant de balise est déjà utilisé." -#: src/tags/mutations/update-tag.js:90 -#: src/tags/mutations/update-tag.js:98 -#: src/tags/mutations/update-tag.js:221 -#: src/tags/mutations/update-tag.js:232 +#: src/tags/data-source.js:30 +#: src/tags/data-source.js:36 +#: src/tags/data-source.js:92 +#: src/tags/data-source.js:101 msgid "Unable to update tag. Please try again." msgstr "Impossible de mettre à jour la balise. Veuillez réessayer." -#: src/domain/mutations/update-domain.js:109 +#: src/domain/mutations/update-domain.js:123 msgid "Unable to update unknown domain." msgstr "Impossible de mettre à jour un domaine inconnu." -#: src/organization/mutations/update-organization.js:140 +#: src/organization/mutations/update-organization.js:137 msgid "Unable to update unknown organization." msgstr "Impossible de mettre à jour une organisation inconnue." -#: src/tags/mutations/update-tag.js:108 +#: src/tags/mutations/update-tag.js:87 msgid "Unable to update unknown tag." msgstr "Impossible de mettre à jour une étiquette inconnue." -#: src/affiliation/mutations/update-user-role.js:128 -#: src/affiliation/mutations/update-user-role.js:150 -#: src/affiliation/mutations/update-user-role.js:202 -#: src/affiliation/mutations/update-user-role.js:212 +#: src/affiliation/mutations/update-user-role.js:130 +#: src/affiliation/mutations/update-user-role.js:152 +#: src/affiliation/mutations/update-user-role.js:196 +#: src/affiliation/mutations/update-user-role.js:206 +#: src/affiliation/mutations/update-user-role.js:217 msgid "Unable to update user's role. Please try again." msgstr "Impossible de mettre à jour le rôle de l'utilisateur. Veuillez réessayer." -#: src/affiliation/mutations/update-user-role.js:67 +#: src/affiliation/mutations/update-user-role.js:69 msgid "Unable to update your own role." msgstr "Impossible de mettre à jour votre propre rôle." @@ -1688,17 +1707,17 @@ msgid "Unable to verify if user is a super admin, please try again." msgstr "Impossible de vérifier si l'utilisateur est un super administrateur, veuillez réessayer." #: src/user/mutations/update-user-profile.js:99 -#: src/user/queries/is-user-admin.js:55 +#: src/user/queries/is-user-admin.js:49 msgid "Unable to verify if user is an admin, please try again." msgstr "Impossible de vérifier si l'utilisateur est un administrateur, veuillez réessayer." -#: src/organization/mutations/verify-organization.js:106 -#: src/organization/mutations/verify-organization.js:123 -#: src/organization/mutations/verify-organization.js:131 +#: src/organization/data-source.js:237 +#: src/organization/data-source.js:252 +#: src/organization/data-source.js:260 msgid "Unable to verify organization. Please try again." msgstr "Impossible de vérifier l'organisation. Veuillez réessayer." -#: src/organization/mutations/verify-organization.js:53 +#: src/organization/mutations/verify-organization.js:50 msgid "Unable to verify unknown organization." msgstr "Impossible de vérifier une organisation inconnue." @@ -1710,7 +1729,7 @@ msgstr "L'utilisateur n'a pas pu être interrogé." msgid "User is trying to register for a non-production environment." msgstr "L'utilisateur essaie de s'enregistrer dans un environnement de non-production." -#: src/affiliation/mutations/update-user-role.js:246 +#: src/affiliation/mutations/update-user-role.js:253 msgid "User role was updated successfully." msgstr "Le rôle de l'utilisateur a été mis à jour avec succès." @@ -1719,11 +1738,11 @@ msgstr "Le rôle de l'utilisateur a été mis à jour avec succès." msgid "Username not available, please try another." msgstr "Le nom d'utilisateur n'est pas disponible, veuillez en essayer un autre." -#: src/auth/tfa-required.js:15 +#: src/auth/guards/tfa-required.js:15 msgid "Verification error. Please activate multi-factor authentication to access content." msgstr "Erreur de vérification. Veuillez activer l'authentification multifactorielle pour accéder au contenu." -#: src/auth/verified-required.js:15 +#: src/auth/guards/verified-required.js:15 msgid "Verification error. Please verify your account via email to access content." msgstr "Erreur de vérification. Veuillez vérifier votre compte par e-mail pour accéder au contenu." @@ -1760,8 +1779,8 @@ msgstr "Vous devez fournir une valeur `first` ou `last` pour paginer correctemen msgid "You must provide a `first` or `last` value to properly paginate the `DmarcSummaries` connection." msgstr "Vous devez fournir une valeur `first` ou `last` pour paginer correctement la connexion `DmarcSummaries`." -#: src/domain/loaders/load-domain-connections-by-organizations-id.js:140 -#: src/domain/loaders/load-domain-connections-by-user-id.js:165 +#: src/domain/loaders/load-domain-connections-by-organizations-id.js:141 +#: src/domain/loaders/load-domain-connections-by-user-id.js:166 msgid "You must provide a `first` or `last` value to properly paginate the `Domain` connection." msgstr "Vous devez fournir une valeur `first` ou `last` pour paginer correctement la connexion `Domain`." @@ -1822,8 +1841,8 @@ msgid "You must provide a `limit` value in the range of 1-100 to properly pagina msgstr "Vous devez fournir une valeur `limit` comprise entre 1 et 100 pour paginer correctement la connexion `DNS`." #: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:16 -msgid "You must provide a `limit` value in the range of 1-100 to properly paginate the `MXRecord` connection." -msgstr "Vous devez fournir une valeur `limit` comprise entre 1 et 100 pour paginer correctement la connexion `MXRecord`." +#~ msgid "You must provide a `limit` value in the range of 1-100 to properly paginate the `MXRecord` connection." +#~ msgstr "Vous devez fournir une valeur `limit` comprise entre 1 et 100 pour paginer correctement la connexion `MXRecord`." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:16 msgid "You must provide a `limit` value in the range of 1-100 to properly paginate the `web` connection." @@ -1834,8 +1853,8 @@ msgid "You must provide a `limit` value to properly paginate the `DNS` connectio msgstr "Vous devez fournir une valeur `limit` pour paginer correctement la connexion `DNS`." #: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:9 -msgid "You must provide a `limit` value to properly paginate the `MXRecord` connection." -msgstr "Vous devez fournir une valeur `limit` pour paginer correctement la connexion `MXRecord`." +#~ msgid "You must provide a `limit` value to properly paginate the `MXRecord` connection." +#~ msgstr "Vous devez fournir une valeur `limit` pour paginer correctement la connexion `MXRecord`." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:9 msgid "You must provide a `limit` value to properly paginate the `web` connection." @@ -1870,8 +1889,8 @@ msgid "You must provide at most one pagination method (`before`, `after`, `offse msgstr "Vous devez fournir au plus une valeur de méthode de pagination (`before`, `after`, `offset`) pour paginer correctement la connexion `DNS`." #: src/dns-scan/loaders/load-mx-record-diff-by-domain-id.js:30 -msgid "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `MXRecord` connection." -msgstr "Vous devez fournir au plus une valeur de méthode de pagination (`before`, `after`, `offset`) pour paginer correctement la connexion `MXRecord`." +#~ msgid "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `MXRecord` connection." +#~ msgstr "Vous devez fournir au plus une valeur de méthode de pagination (`before`, `after`, `offset`) pour paginer correctement la connexion `MXRecord`." #: src/web-scan/loaders/load-web-connections-by-domain-id.js:30 msgid "You must provide at most one pagination method (`before`, `after`, `offset`) value to properly paginate the `web` connection." diff --git a/api/src/notify/index.js b/api/src/notify/index.js index c2bd257bb1..9e306a9a0a 100644 --- a/api/src/notify/index.js +++ b/api/src/notify/index.js @@ -7,3 +7,4 @@ export * from './notify-send-org-invite-email' export * from './notify-send-password-reset-email' export * from './notify-send-updated-username-email' export * from './notify-send-verification-email' +export * from './notify-send-role-change-email' diff --git a/api/src/notify/notify-send-role-change-email.js b/api/src/notify/notify-send-role-change-email.js new file mode 100644 index 0000000000..473339b698 --- /dev/null +++ b/api/src/notify/notify-send-role-change-email.js @@ -0,0 +1,20 @@ +const { NOTIFICATION_ROLE_CHANGE_EMAIL } = process.env + +export const sendRoleChangeEmail = + ({ notifyClient }) => + async ({ user, orgNames, oldRole, newRole }) => { + try { + await notifyClient.sendEmail(NOTIFICATION_ROLE_CHANGE_EMAIL, user.userName, { + personalisation: { + display_name: user.displayName, + org_name_en: orgNames.orgNameEN, + org_name_fr: orgNames.orgNameFR, + old_role: oldRole, + new_role: newRole, + }, + }) + return true + } catch (err) { + console.error(`Error occurred when sending role update email for ${user._key}: ${err}`) + } + } diff --git a/api/src/organization/data-source.js b/api/src/organization/data-source.js new file mode 100644 index 0000000000..166622e7fd --- /dev/null +++ b/api/src/organization/data-source.js @@ -0,0 +1,501 @@ +import { t } from '@lingui/macro' + +import { + loadAllOrganizationDomainStatuses, + loadOrgByKey, + loadOrgBySlug, + loadOrgConnectionsByDomainId, + loadOrgConnectionsByUserId, + loadOrganizationDomainStatuses, + loadOrganizationNamesById, + loadOrganizationSummariesByPeriod, +} from './loaders' + +export class OrganizationDataSource { + constructor({ query, userKey, i18n, language, cleanseInput, loginRequiredBool, transaction, collections }) { + this._query = query + this._userKey = userKey + this._i18n = i18n + this._transaction = transaction + this._collections = collections + this.byKey = loadOrgByKey({ query, language, userKey, i18n }) + this.bySlug = loadOrgBySlug({ query, language, userKey, i18n }) + this.connectionsByDomainId = loadOrgConnectionsByDomainId({ query, language, userKey, cleanseInput, i18n, auth: { loginRequiredBool } }) + this.connectionsByUserId = loadOrgConnectionsByUserId({ query, userKey, cleanseInput, language, i18n, auth: { loginRequiredBool } }) + this.summariesByPeriod = loadOrganizationSummariesByPeriod({ query, userKey, cleanseInput, i18n }) + this.namesById = loadOrganizationNamesById({ query, userKey, i18n }) + this.domainStatuses = loadOrganizationDomainStatuses({ query, userKey, i18n }) + this.allDomainStatuses = loadAllOrganizationDomainStatuses({ query, userKey, i18n, language }) + } + + async create({ organizationDetails, userId, language }) { + const trx = await this._transaction(this._collections) + + let cursor + try { + cursor = await trx.step( + () => this._query` + WITH organizations + INSERT ${organizationDetails} INTO organizations + RETURN MERGE( + { + _id: NEW._id, + _key: NEW._key, + _rev: NEW._rev, + _type: "organization", + id: NEW._key, + verified: NEW.verified, + domainCount: 0, + summaries: NEW.summaries + }, + TRANSLATE(${language}, NEW.orgDetails) + ) + `, + ) + } catch (err) { + console.error(`Database error occurred when user: ${this._userKey} was creating new organization: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to create organization. Please try again.`)) + } + const organization = await cursor.next() + + try { + await trx.step( + () => this._query` + WITH affiliations, organizations, users + INSERT { + _from: ${organization._id}, + _to: ${userId}, + permission: "owner", + } INTO affiliations + `, + ) + } catch (err) { + console.error(`Database error occurred when inserting affiliation for user: ${this._userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to create organization. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Transaction error occurred when committing new organization for user: ${this._userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to create organization. Please try again.`)) + } + + return organization + } + + async checkNameInUse({ nameEN, nameFR }) { + let cursor + try { + cursor = await this._query` + WITH organizations + FOR org IN organizations + FILTER (org.orgDetails.en.name == ${nameEN}) OR (org.orgDetails.fr.name == ${nameFR}) + RETURN org + ` + } catch (err) { + console.error(`Database error occurred during name check for user: ${this._userKey}: ${err}`) + throw new Error(this._i18n._(t`Unable to update organization. Please try again.`)) + } + return cursor + } + + async getRawByKey({ orgKey }) { + let cursor + try { + cursor = await this._query` + WITH organizations + FOR org IN organizations + FILTER org._key == ${orgKey} + RETURN org + ` + } catch (err) { + console.error(`Database error occurred while retrieving org: ${orgKey} for user: ${this._userKey}: ${err}`) + throw new Error(this._i18n._(t`Unable to load organization. Please try again.`)) + } + + try { + return await cursor.next() + } catch (err) { + console.error(`Cursor error occurred while retrieving org: ${orgKey} for user: ${this._userKey}: ${err}`) + throw new Error(this._i18n._(t`Unable to load organization. Please try again.`)) + } + } + + async update({ orgKey, updatedOrgDetails }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH organizations + UPSERT { _key: ${orgKey} } + INSERT ${updatedOrgDetails} + UPDATE ${updatedOrgDetails} + IN organizations + `, + ) + } catch (err) { + console.error(`Transaction error occurred while upserting org: ${orgKey} for user: ${this._userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to load organization. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Transaction error occurred while committing org: ${orgKey} for user: ${this._userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to load organization. Please try again.`)) + } + } + + async archive({ organization }) { + const trx = await this._transaction(this._collections) + + let domainInfo + try { + const countCursor = await this._query` + WITH claims, domains, organizations + LET domainIds = ( + FOR v, e IN 1..1 OUTBOUND ${organization._id} claims + RETURN e._to + ) + FOR domain IN domains + FILTER domain._id IN domainIds + LET count = LENGTH( + FOR v, e IN 1..1 INBOUND domain._id claims + RETURN 1 + ) + RETURN { _id: domain._id, _key: domain._key, count } + ` + domainInfo = await countCursor.all() + } catch (err) { + console.error(`Database error occurred for user: ${this._userKey} while gathering domain count for archive of org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to archive organization. Please try again.`)) + } + + for (const domain of domainInfo) { + if (domain.count === 1) { + try { + await trx.step( + () => this._query` + WITH domains + UPDATE { _key: ${domain._key}, archived: true } IN domains + `, + ) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while archiving domains for org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to archive organization. Please try again.`)) + } + } + } + + try { + await trx.step( + () => this._query` + WITH organizations + UPDATE { _key: ${organization._key}, verified: false } IN organizations + `, + ) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while unverifying org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to archive organization. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Transaction commit error occurred for user: ${this._userKey} while archiving org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to archive organization. Please try again.`)) + } + } + + async verify({ currentOrg }) { + const trx = await this._transaction(this._collections) + + try { + await trx.step( + () => this._query` + WITH organizations + UPSERT { _key: ${currentOrg._key} } + INSERT ${currentOrg} + UPDATE ${currentOrg} + IN organizations + `, + ) + } catch (err) { + console.error(`Transaction error occurred while upserting verified org: ${currentOrg._key} for user: ${this._userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to verify organization. Please try again.`)) + } + + try { + await trx.step( + () => this._query` + WITH domains, claims + FOR v, e IN 1..1 OUTBOUND ${currentOrg._id} claims + FILTER v.archived == true + UPDATE v WITH { archived: false } IN domains + `, + ) + } catch (err) { + console.error(`Transaction error occurred while unarchiving affiliated domains for org: ${currentOrg._key} for user: ${this._userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to verify organization. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Transaction error occurred while committing verified org: ${currentOrg._key} for user: ${this._userKey}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to verify organization. Please try again.`)) + } + } + + async remove({ organization }) { + const trx = await this._transaction(this._collections) + + let dmarcSummaryCheckList + try { + const dmarcSummaryCheckCursor = await this._query` + WITH domains, ownership, dmarcSummaries, organizations + FOR v, e IN 1..1 OUTBOUND ${organization._id} ownership + RETURN e + ` + dmarcSummaryCheckList = await dmarcSummaryCheckCursor.all() + } catch (err) { + console.error(`Database error occurred for user: ${this._userKey} while getting dmarc summaries for org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + for (const ownership of dmarcSummaryCheckList) { + try { + await trx.step( + () => this._query` + WITH ownership, organizations, domains, dmarcSummaries, domainsToDmarcSummaries + LET dmarcSummaryEdges = ( + FOR v, e IN 1..1 OUTBOUND ${ownership._to} domainsToDmarcSummaries + RETURN { edgeKey: e._key, dmarcSummaryId: e._to } + ) + LET removeDmarcSummaryEdges = ( + FOR dmarcSummaryEdge IN dmarcSummaryEdges + REMOVE dmarcSummaryEdge.edgeKey IN domainsToDmarcSummaries + OPTIONS { waitForSync: true } + ) + LET removeDmarcSummary = ( + FOR dmarcSummaryEdge IN dmarcSummaryEdges + LET key = PARSE_IDENTIFIER(dmarcSummaryEdge.dmarcSummaryId).key + REMOVE key IN dmarcSummaries + OPTIONS { waitForSync: true } + ) + RETURN true + `, + ) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing dmarc summaries for org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + try { + await trx.step( + () => this._query` + WITH ownership, organizations, domains + REMOVE ${ownership._key} IN ownership + OPTIONS { waitForSync: true } + `, + ) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing ownerships for org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + } + + let domainInfo + try { + const countCursor = await this._query` + WITH claims, domains, organizations + LET domainIds = ( + FOR v, e IN 1..1 OUTBOUND ${organization._id} claims + RETURN e._to + ) + FOR domain IN domains + FILTER domain._id IN domainIds + LET count = LENGTH( + FOR v, e IN 1..1 INBOUND domain._id claims + RETURN 1 + ) + RETURN { + "_id": domain._id, + "_key": domain._key, + "domain": domain.domain, + "count": count + } + ` + domainInfo = await countCursor.all() + } catch (err) { + console.error(`Database error occurred for user: ${this._userKey} while gathering domain count for removal of org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + for (const domain of domainInfo) { + if (domain.count === 1) { + try { + await trx.step(async () => { + await this._query` + WITH web, webScan + FOR webV, domainsWebEdge IN 1..1 OUTBOUND ${domain._id} domainsWeb + LET removeWebScansQuery = ( + FOR webScanV, webToWebScansV In 1..1 OUTBOUND webV._id webToWebScans + REMOVE webScanV IN webScan + REMOVE webToWebScansV IN webToWebScans + OPTIONS { waitForSync: true } + ) + REMOVE webV IN web + REMOVE domainsWebEdge IN domainsWeb + OPTIONS { waitForSync: true } + ` + }) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing web data for ${domain.domain} in org: ${organization.slug}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + try { + await trx.step(async () => { + await this._query` + WITH dns + FOR dnsV, domainsDNSEdge IN 1..1 OUTBOUND ${domain._id} domainsDNS + REMOVE dnsV IN dns + REMOVE domainsDNSEdge IN domainsDNS + OPTIONS { waitForSync: true } + ` + }) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing DNS data for ${domain.domain} in org: ${organization.slug}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + try { + await trx.step(async () => { + await this._query` + WITH favourites, domains + FOR fav IN favourites + FILTER fav._to == ${domain._id} + REMOVE fav IN favourites + ` + }) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing favourites for ${domain.domain} in org: ${organization.slug}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + try { + await trx.step(async () => { + await this._query` + FOR e IN domainsToSelectors + FILTER e._from == ${domain._id} + REMOVE e IN domainsToSelectors + ` + }) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing DKIM selectors for ${domain.domain} in org: ${organization.slug}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + try { + await trx.step( + () => this._query` + WITH claims, domains, organizations + LET domainEdges = ( + FOR v, e IN 1..1 OUTBOUND ${organization._id} claims + FILTER e._to == ${domain._id} + RETURN { edgeKey: e._key, domainId: e._to } + ) + LET removeDomainEdges = ( + FOR domainEdge in domainEdges + REMOVE domainEdge.edgeKey IN claims + OPTIONS { waitForSync: true } + ) + LET removeDomain = ( + FOR domainEdge in domainEdges + LET key = PARSE_IDENTIFIER(domainEdge.domainId).key + REMOVE key IN domains + OPTIONS { waitForSync: true } + ) + RETURN true + `, + ) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing domains for org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + } + } + + try { + await trx.step( + () => this._query` + WITH affiliations, organizations, users + LET userEdges = ( + FOR v, e IN 1..1 OUTBOUND ${organization._id} affiliations + RETURN { edgeKey: e._key, userKey: e._to } + ) + LET removeUserEdges = ( + FOR userEdge IN userEdges + REMOVE userEdge.edgeKey IN affiliations + OPTIONS { waitForSync: true } + ) + RETURN true + `, + ) + + await trx.step( + () => this._query` + WITH organizations, organizationSummaries + FOR summary in organizationSummaries + FILTER summary.organization == ${organization._id} + REMOVE summary._key IN organizationSummaries + OPTIONS { waitForSync: true } + `, + ) + + await trx.step( + () => this._query` + WITH organizations + REMOVE ${organization._key} IN organizations + OPTIONS { waitForSync: true } + `, + ) + } catch (err) { + console.error(`Transaction error occurred for user: ${this._userKey} while removing affiliations and org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + + try { + await trx.commit() + } catch (err) { + console.error(`Transaction commit error occurred for user: ${this._userKey} while removing org: ${organization._key}: ${err}`) + await trx.abort() + throw new Error(this._i18n._(t`Unable to remove organization. Please try again.`)) + } + } +} diff --git a/api/src/organization/index.js b/api/src/organization/index.js index e170187ec3..9366445c50 100644 --- a/api/src/organization/index.js +++ b/api/src/organization/index.js @@ -1,3 +1,4 @@ +export * from './data-source' export * from './inputs' export * from './loaders' export * from './mutations' diff --git a/api/src/organization/loaders/index.js b/api/src/organization/loaders/index.js index 1e5991965b..82b0be23f5 100644 --- a/api/src/organization/loaders/index.js +++ b/api/src/organization/loaders/index.js @@ -5,3 +5,4 @@ export * from './load-organization-connections-by-user-id' export * from './load-all-organization-domain-statuses' export * from './load-organization-domain-statuses' export * from './load-organization-summaries-by-period' +export * from './load-organization-names-by-id' diff --git a/api/src/organization/loaders/load-organization-domain-statuses.js b/api/src/organization/loaders/load-organization-domain-statuses.js index 94a8ec947d..f0009becb3 100644 --- a/api/src/organization/loaders/load-organization-domain-statuses.js +++ b/api/src/organization/loaders/load-organization-domain-statuses.js @@ -90,6 +90,11 @@ export const loadOrganizationDomainStatuses = ${domainFilters} FILTER v.cveDetected ${comparison} true ` + } else if (filterValue === 'cvd-enrolled') { + domainFilters = aql` + ${domainFilters} + FILTER v.cvdEnrollment.status ${comparison} "enrolled" + ` } else if (filterValue === 'scan-pending') { domainFilters = aql`${domainFilters}` } else if (filterValue === 'archived') { @@ -125,7 +130,7 @@ export const loadOrganizationDomainStatuses = WITH claims, domains, organizations FOR v, e IN 1..1 OUTBOUND ${orgId} claims ${archivedFilter} - LET negativeTags = APPEND(v.negativeTags.dns, v.negativeTags.web) + LET negativeTags = APPEND(v.negativeTags.dns, v.negativeTags.web) ${domainFilters} LET ipAddresses = FIRST( FILTER v.latestDnsScan @@ -157,7 +162,8 @@ export const loadOrganizationDomainStatuses = wildcardSibling: v.wildcardSibling, wildcardEntry: v.wildcardEntry, hasEntrustCertificate: v.hasEntrustCertificate, - top25Vulnerabilities: vulnerabilities + top25Vulnerabilities: vulnerabilities, + cvdEnrollmentStatus: v.cvdEnrollment.status } ` ).all() diff --git a/api/src/organization/loaders/load-organization-names-by-id.js b/api/src/organization/loaders/load-organization-names-by-id.js new file mode 100644 index 0000000000..037ff5a474 --- /dev/null +++ b/api/src/organization/loaders/load-organization-names-by-id.js @@ -0,0 +1,33 @@ +import DataLoader from 'dataloader' +import { t } from '@lingui/macro' + +export const loadOrganizationNamesById = ({ query, userKey, i18n }) => + new DataLoader(async (ids) => { + let cursor + try { + cursor = await query` + FOR orgId IN ${ids} + LET org = DOCUMENT(organizations, orgId) + RETURN { + orgId, + orgNameEN: org.orgDetails.en.name, + orgNameFR: org.orgDetails.fr.name, + } + ` + } catch (err) { + console.error(`Database error occurred when user: ${userKey} running loadOrganizationNamesById: ${err}`) + throw new Error(i18n._(t`Unable to load organization names. Please try again.`)) + } + + const orgMap = {} + try { + await cursor.forEach((org) => { + orgMap[org.orgId] = org + }) + } catch (err) { + console.error(`Cursor error occurred when user: ${userKey} during loadOrganizationNamesById: ${err}`) + throw new Error(i18n._(t`Unable to load organization names. Please try again.`)) + } + + return ids.map((id) => orgMap[id]) + }) diff --git a/api/src/organization/mutations/__tests__/archive-organization.test.js b/api/src/organization/mutations/__tests__/archive-organization.test.js index 9e1f992a0a..e574daa6ff 100644 --- a/api/src/organization/mutations/__tests__/archive-organization.test.js +++ b/api/src/organization/mutations/__tests__/archive-organization.test.js @@ -11,7 +11,7 @@ import frenchMessages from '../../../locale/fr/messages' import { cleanseInput } from '../../../validators' import { checkPermission, userRequired, verifiedRequired } from '../../../auth' import { loadUserByKey } from '../../../user/loaders' -import { loadOrgByKey } from '../../loaders' +import { OrganizationDataSource } from '../../data-source' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -176,8 +176,18 @@ describe('archiving an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -242,8 +252,18 @@ describe('archiving an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -315,11 +335,9 @@ describe('archiving an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue(undefined), - }, - }, + } } }, }, }) @@ -383,8 +401,7 @@ describe('archiving an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, verified: true, @@ -411,8 +428,7 @@ describe('archiving an organization', () => { }, }, }), - }, - }, + } } }, }, }) @@ -437,20 +453,8 @@ describe('archiving an organization', () => { }) }) }) - describe('given a trx commit error', () => { + describe('given a data source error', () => { it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValueOnce([]).mockReturnValue([]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Commit Error')), - abort: jest.fn(), - }) - const response = await graphql({ schema, source: ` @@ -478,9 +482,6 @@ describe('archiving an organization', () => { rootValue: null, contextValue: { i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, userKey: 123, request: { ip: '127.0.0.1' }, auth: { @@ -489,34 +490,18 @@ describe('archiving an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), + dataSources: { + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + _id: 'organizations/123', + _key: 123, + verified: false, + slug: 'treasury-board-secretariat', + name: 'Treasury Board of Canada Secretariat', + }), + }, + archive: jest.fn().mockRejectedValue(new Error('Unable to archive organization. Please try again.')), }, }, }, @@ -525,9 +510,7 @@ describe('archiving an organization', () => { const error = [new GraphQLError('Unable to archive organization. Please try again.')] expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred for user: 123 while attempting archive of org: 123, Error: Commit Error`, - ]) + expect(consoleOutput).toEqual([]) }) }) }) diff --git a/api/src/organization/mutations/__tests__/create-organization.test.js b/api/src/organization/mutations/__tests__/create-organization.test.js index 330dfacde7..3ab87077a2 100644 --- a/api/src/organization/mutations/__tests__/create-organization.test.js +++ b/api/src/organization/mutations/__tests__/create-organization.test.js @@ -9,16 +9,16 @@ import { createMutationSchema } from '../../../mutation' import englishMessages from '../../../locale/en/messages' import frenchMessages from '../../../locale/fr/messages' import { cleanseInput, slugify } from '../../../validators' -import { userRequired, verifiedRequired } from '../../../auth' +import { checkSuperAdmin, superAdminRequired, userRequired, verifiedRequired } from '../../../auth' import { loadUserByKey } from '../../../user/loaders' -import { loadOrgBySlug } from '../../loaders' +import { OrganizationDataSource } from '../../data-source' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' const { DB_PASS: rootPass, DB_URL: url, SIGN_IN_KEY } = process.env describe('create an organization', () => { - let query, drop, truncate, schema, collections, transaction, user + let query, drop, truncate, schema, collections, transaction, user, i18n const consoleOutput = [] const mockedInfo = (output) => consoleOutput.push(output) @@ -33,6 +33,18 @@ describe('create an organization', () => { query: createQuerySchema(), mutation: createMutationSchema(), }) + i18n = setupI18n({ + locale: 'en', + localeData: { + en: { plurals: {} }, + fr: { plurals: {} }, + }, + locales: ['en', 'fr'], + messages: { + en: englishMessages.messages, + fr: frenchMessages.messages, + }, + }) }) afterEach(() => { consoleOutput.length = 0 @@ -74,16 +86,8 @@ describe('create an organization', () => { acronymFR: "SCT" nameEN: "Treasury Board of Canada Secretariat" nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" + externalId: "EXT123" + verified: false } ) { result { @@ -92,12 +96,8 @@ describe('create an organization', () => { acronym slug name - zone - sector - country - province - city verified + externalId } } } @@ -107,6 +107,7 @@ describe('create an organization', () => { contextValue: { request: { language: 'en', + ip: '1.2.3.4', }, query, collections: collectionNames, @@ -118,9 +119,22 @@ describe('create an organization', () => { loadUserByKey: loadUserByKey({ query }), }), verifiedRequired: verifiedRequired({}), + checkSuperAdmin: checkSuperAdmin({ i18n, query, userKey: user._key }), + superAdminRequired: superAdminRequired({ i18n }), + }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), }, loaders: { - loadOrgBySlug: loadOrgBySlug({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, validators: { @@ -146,17 +160,15 @@ describe('create an organization', () => { acronym: org.acronym, slug: org.slug, name: org.name, - zone: org.zone, - sector: org.sector, - country: org.country, - province: org.province, - city: org.city, verified: org.verified, + externalId: org.externalId, }, }, }, } + // externalId is returned as null if not set, not undefined + expectedResponse.data.createOrganization.result.externalId = null expect(response).toEqual(expectedResponse) expect(consoleOutput).toEqual([`User: ${user._key} successfully created a new organization: ${org.slug}`]) }) @@ -173,16 +185,8 @@ describe('create an organization', () => { acronymFR: "SCT" nameEN: "Treasury Board of Canada Secretariat" nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" + externalId: "EXT123" + verified: false } ) { result { @@ -191,12 +195,8 @@ describe('create an organization', () => { acronym slug name - zone - sector - country - province - city verified + externalId } } } @@ -206,6 +206,7 @@ describe('create an organization', () => { contextValue: { request: { language: 'fr', + ip: '1.2.3.4', }, query, collections: collectionNames, @@ -217,9 +218,22 @@ describe('create an organization', () => { loadUserByKey: loadUserByKey({ query }), }), verifiedRequired: verifiedRequired({}), + checkSuperAdmin: checkSuperAdmin({ i18n, query, userKey: user._key }), + superAdminRequired: superAdminRequired({ i18n }), + }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'fr', + cleanseInput, + transaction, + collections: collectionNames, + }), }, loaders: { - loadOrgBySlug: loadOrgBySlug({ query, language: 'fr' }), loadUserByKey: loadUserByKey({ query }), }, validators: { @@ -245,17 +259,15 @@ describe('create an organization', () => { acronym: org.acronym, slug: org.slug, name: org.name, - zone: org.zone, - sector: org.sector, - country: org.country, - province: org.province, - city: org.city, verified: org.verified, + externalId: org.externalId, }, }, }, } + // externalId is returned as null if not set, not undefined + expectedResponse.data.createOrganization.result.externalId = null expect(response).toEqual(expectedResponse) expect(consoleOutput).toEqual([ `User: ${user._key} successfully created a new organization: treasury-board-of-canada-secretariat`, @@ -264,22 +276,7 @@ describe('create an organization', () => { }) }) describe('given an unsuccessful org creation', () => { - let i18n describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) describe('organization already exists', () => { it('returns an error', async () => { const response = await graphql({ @@ -292,16 +289,6 @@ describe('create an organization', () => { acronymFR: "SCT" nameEN: "Treasury Board of Canada Secretariat" nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" } ) { result { @@ -310,11 +297,6 @@ describe('create an organization', () => { acronym slug name - zone - sector - country - province - city verified } ... on OrganizationError { @@ -340,11 +322,11 @@ describe('create an organization', () => { _key: 123, }), verifiedRequired: jest.fn(), + checkSuperAdmin: jest.fn(), + superAdminRequired: jest.fn(), }, + dataSources: { organization: { bySlug: { loadMany: jest.fn().mockReturnValue([{}, undefined]) } } }, loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([{}, undefined]), - }, loadUserByKey: jest.fn(), }, validators: { @@ -371,265 +353,61 @@ describe('create an organization', () => { ]) }) }) - describe('transaction error occurs', () => { - describe('when inserting organization', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createOrganization( - input: { - acronymEN: "TBS" - acronymFR: "SCT" - nameEN: "Treasury Board of Canada Secretariat" - nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" - } - ) { - result { - ... on Organization { - id - acronym - slug - name - zone - sector - country - province - city - verified - } - ... on OrganizationError { - code - description - } - } + describe('data source error occurs', () => { + it('returns an error', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + createOrganization( + input: { + acronymEN: "TBS" + acronymFR: "SCT" + nameEN: "Treasury Board of Canada Secretariat" + nameFR: "Secrétariat du Conseil Trésor du Canada" } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - verifiedRequired: jest.fn(), - }, - loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([undefined, undefined]), - }, - loadUserByKey: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - }, - }) - - const error = [new GraphQLError('Unable to create organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred when user: 123 was creating new organization treasury-board-of-canada-secretariat: Error: trx step error`, - ]) - }) - }) - describe('when inserting edge', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createOrganization( - input: { - acronymEN: "TBS" - acronymFR: "SCT" - nameEN: "Treasury Board of Canada Secretariat" - nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" + ) { + result { + ... on Organization { + id + acronym + slug + name + verified } - ) { - result { - ... on Organization { - id - acronym - slug - name - zone - sector - country - province - city - verified - } - ... on OrganizationError { - code - description - } + ... on OrganizationError { + code + description } } } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({ next: jest.fn() }) - .mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - verifiedRequired: jest.fn(), - }, - loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([undefined, undefined]), - }, - loadUserByKey: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, + } + `, + rootValue: null, + contextValue: { + i18n, + request: { language: 'en' }, + userKey: 123, + auth: { + userRequired: jest.fn().mockReturnValue({ _key: 123 }), + verifiedRequired: jest.fn(), + checkSuperAdmin: jest.fn(), + superAdminRequired: jest.fn(), }, - }) - - const error = [new GraphQLError('Unable to create organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred when inserting edge definition for user: 123 to treasury-board-of-canada-secretariat: Error: trx step error`, - ]) - }) - }) - describe('when committing information to db', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createOrganization( - input: { - acronymEN: "TBS" - acronymFR: "SCT" - nameEN: "Treasury Board of Canada Secretariat" - nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" - } - ) { - result { - ... on Organization { - id - acronym - slug - name - zone - sector - country - province - city - verified - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({ next: jest.fn() }), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - verifiedRequired: jest.fn(), - }, - loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([undefined, undefined]), - }, - loadUserByKey: jest.fn(), - }, - validators: { - cleanseInput, - slugify, + dataSources: { + organization: { + bySlug: { loadMany: jest.fn().mockReturnValue([undefined, undefined]) }, + create: jest.fn().mockRejectedValue(new Error('Unable to create organization. Please try again.')), }, }, - }) + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Unable to create organization. Please try again.')] + const error = [new GraphQLError('Unable to create organization. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred when committing new organization: treasury-board-of-canada-secretariat for user: 123 to db: Error: trx commit error`, - ]) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([]) }) }) }) @@ -660,16 +438,6 @@ describe('create an organization', () => { acronymFR: "SCT" nameEN: "Treasury Board of Canada Secretariat" nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" } ) { result { @@ -678,11 +446,6 @@ describe('create an organization', () => { acronym slug name - zone - sector - country - province - city verified } ... on OrganizationError { @@ -708,11 +471,11 @@ describe('create an organization', () => { _key: 123, }), verifiedRequired: jest.fn(), + checkSuperAdmin: jest.fn(), + superAdminRequired: jest.fn(), }, + dataSources: { organization: { bySlug: { loadMany: jest.fn().mockReturnValue([{}, undefined]) } } }, loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([{}, undefined]), - }, loadUserByKey: jest.fn(), }, validators: { @@ -739,265 +502,61 @@ describe('create an organization', () => { ]) }) }) - describe('transaction error occurs', () => { - describe('when inserting organization', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createOrganization( - input: { - acronymEN: "TBS" - acronymFR: "SCT" - nameEN: "Treasury Board of Canada Secretariat" - nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" - } - ) { - result { - ... on Organization { - id - acronym - slug - name - zone - sector - country - province - city - verified - } - ... on OrganizationError { - code - description - } - } + describe('data source error occurs', () => { + it('returns an error', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + createOrganization( + input: { + acronymEN: "TBS" + acronymFR: "SCT" + nameEN: "Treasury Board of Canada Secretariat" + nameFR: "Secrétariat du Conseil Trésor du Canada" } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - verifiedRequired: jest.fn(), - }, - loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([undefined, undefined]), - }, - loadUserByKey: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - }, - }) - - const error = [new GraphQLError('Impossible de créer une organisation. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred when user: 123 was creating new organization treasury-board-of-canada-secretariat: Error: trx step error`, - ]) - }) - }) - describe('when inserting edge', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createOrganization( - input: { - acronymEN: "TBS" - acronymFR: "SCT" - nameEN: "Treasury Board of Canada Secretariat" - nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" + ) { + result { + ... on Organization { + id + acronym + slug + name + verified } - ) { - result { - ... on Organization { - id - acronym - slug - name - zone - sector - country - province - city - verified - } - ... on OrganizationError { - code - description - } + ... on OrganizationError { + code + description } } } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({ next: jest.fn() }) - .mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - verifiedRequired: jest.fn(), - }, - loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([undefined, undefined]), - }, - loadUserByKey: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, + } + `, + rootValue: null, + contextValue: { + i18n, + request: { language: 'en' }, + userKey: 123, + auth: { + userRequired: jest.fn().mockReturnValue({ _key: 123 }), + verifiedRequired: jest.fn(), + checkSuperAdmin: jest.fn(), + superAdminRequired: jest.fn(), }, - }) - - const error = [new GraphQLError('Impossible de créer une organisation. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred when inserting edge definition for user: 123 to treasury-board-of-canada-secretariat: Error: trx step error`, - ]) - }) - }) - describe('when committing information to db', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - createOrganization( - input: { - acronymEN: "TBS" - acronymFR: "SCT" - nameEN: "Treasury Board of Canada Secretariat" - nameFR: "Secrétariat du Conseil Trésor du Canada" - zoneEN: "FED" - zoneFR: "FED" - sectorEN: "TBS" - sectorFR: "TBS" - countryEN: "Canada" - countryFR: "Canada" - provinceEN: "Ontario" - provinceFR: "Ontario" - cityEN: "Ottawa" - cityFR: "Ottawa" - } - ) { - result { - ... on Organization { - id - acronym - slug - name - zone - sector - country - province - city - verified - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - request: { - language: 'en', - }, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({ next: jest.fn() }), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - userRequired: jest.fn().mockReturnValue({ - _key: 123, - }), - verifiedRequired: jest.fn(), - }, - loaders: { - loadOrgBySlug: { - loadMany: jest.fn().mockReturnValue([undefined, undefined]), - }, - loadUserByKey: jest.fn(), - }, - validators: { - cleanseInput, - slugify, + dataSources: { + organization: { + bySlug: { loadMany: jest.fn().mockReturnValue([undefined, undefined]) }, + create: jest.fn().mockRejectedValue(new Error('Impossible de créer une organisation. Veuillez réessayer.')), }, }, - }) + validators: { cleanseInput, slugify }, + }, + }) - const error = [new GraphQLError('Impossible de créer une organisation. Veuillez réessayer.')] + const error = [new GraphQLError('Impossible de créer une organisation. Veuillez réessayer.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred when committing new organization: treasury-board-of-canada-secretariat for user: 123 to db: Error: trx commit error`, - ]) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([]) }) }) }) diff --git a/api/src/organization/mutations/__tests__/remove-organization.test.js b/api/src/organization/mutations/__tests__/remove-organization.test.js index b0b3641d81..7b179c6d81 100644 --- a/api/src/organization/mutations/__tests__/remove-organization.test.js +++ b/api/src/organization/mutations/__tests__/remove-organization.test.js @@ -11,7 +11,7 @@ import frenchMessages from '../../../locale/fr/messages' import { cleanseInput } from '../../../validators' import { checkPermission, userRequired, verifiedRequired } from '../../../auth' import { loadUserByKey } from '../../../user/loaders' -import { loadOrgByKey } from '../../loaders' +import { OrganizationDataSource } from '../../data-source' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -209,8 +209,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -274,8 +285,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -333,8 +355,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -400,8 +433,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -458,8 +502,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -522,8 +577,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -580,8 +646,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -653,8 +730,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -709,8 +797,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -768,8 +867,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -826,8 +936,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -950,8 +1071,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1015,8 +1147,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1074,8 +1217,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1141,8 +1295,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1197,8 +1362,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1257,8 +1433,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1315,8 +1502,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1388,8 +1586,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1444,8 +1653,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1503,8 +1723,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1561,8 +1792,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1674,8 +1916,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1739,8 +1992,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1798,8 +2062,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1865,8 +2140,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1922,8 +2208,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -1982,8 +2279,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -2040,8 +2348,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -2113,8 +2432,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -2169,8 +2499,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -2228,8 +2569,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -2286,8 +2638,19 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: new OrganizationDataSource({ + query, + userKey: user._key, + i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, + }), + }, loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), }, }, @@ -2366,11 +2729,9 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue(undefined), - }, - }, + } } }, }, }) @@ -2434,8 +2795,7 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, verified: true, @@ -2462,8 +2822,7 @@ describe('removing an organization', () => { }, }, }), - }, - }, + } } }, }, }) @@ -2527,8 +2886,7 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _key: 123, verified: false, @@ -2555,8 +2913,7 @@ describe('removing an organization', () => { }, }, }), - }, - }, + } } }, }, }) @@ -2581,961 +2938,8 @@ describe('removing an organization', () => { }) }) }) - describe('given a database error', () => { - describe('when getting the ownership information', () => { - it('throws an error', async () => { - const mockedQuery = jest.fn().mockRejectedValue(new Error('Database Error')) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred for user: 123 while attempting to get dmarcSummaryInfo while removing org: 123, Error: Database Error`, - ]) - }) - }) - describe('when getting the domain claim count', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValue([]), - } - - const mockedQuery = jest - .fn() - .mockReturnValueOnce(mockedCursor) - .mockRejectedValue(new Error('Database Error')) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred for user: 123 while attempting to gather domain count while removing org: 123, Error: Database Error`, - ]) - }) - }) - }) - describe('given a cursor error', () => { - describe('when getting getting ownership information', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockRejectedValue(new Error('Cursor Error')), - } - - const mockedQuery = jest - .fn() - .mockReturnValueOnce(mockedCursor) - .mockRejectedValue(new Error('Database Error')) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred for user: 123 while attempting to get dmarcSummaryInfo while removing org: 123, Error: Cursor Error`, - ]) - }) - }) - describe('when getting getting domain claim count', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValueOnce([]).mockRejectedValue(new Error('Cursor Error')), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred for user: 123 while attempting to gather domain count while removing org: 123, Error: Cursor Error`, - ]) - }) - }) - }) - describe('given a trx step error', () => { - describe('when removing dmarc summary data', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValue([{}]), - } - - const mockedQuery = jest.fn().mockReturnValueOnce(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Trx Step')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred for user: 123 while attempting to remove dmarc summaries while removing org: 123, Error: Trx Step`, - ]) - }) - }) - describe('when removing ownership data', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValue([{}]), - } - - const mockedQuery = jest.fn().mockReturnValueOnce(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce({}).mockRejectedValue(new Error('Trx Step')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred for user: 123 while attempting to remove ownerships while removing org: 123, Error: Trx Step`, - ]) - }) - }) - describe('when removing web scan results data', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest - .fn() - .mockReturnValueOnce([]) - .mockReturnValue([{ count: 1, domain: 'test.gc.ca' }]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('Trx Step')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred while user: 123 attempted to remove web data for test.gc.ca in org: undefined, Error: Trx Step`, - ]) - }) - }) - describe('when removing scan data', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest - .fn() - .mockReturnValueOnce([]) - .mockReturnValue([{ count: 1, domain: 'test.gc.ca' }]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValueOnce({}).mockRejectedValue(new Error('Trx Step')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred while user: 123 attempted to remove DNS data for test.gc.ca in org: undefined, error: Error: Trx Step`, - ]) - }) - }) - describe('when removing domain', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest - .fn() - .mockReturnValueOnce([]) - .mockReturnValue([{ count: 1 }]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({}) - .mockReturnValueOnce({}) - .mockReturnValueOnce({}) - .mockReturnValueOnce({}) - .mockRejectedValue(new Error('Trx Step')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred for user: 123 while attempting to remove domains while removing org: 123, Error: Trx Step`, - ]) - }) - }) - describe('when removing affiliations and org', () => { - it('throws an error', async () => { - const mockedCursor = { - all: jest - .fn() - .mockReturnValueOnce([]) - .mockReturnValue([{ count: 1 }]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest - .fn() - .mockReturnValueOnce({}) - .mockReturnValueOnce({}) - .mockReturnValueOnce({}) - .mockReturnValueOnce({}) - .mockReturnValueOnce({}) - .mockRejectedValue(new Error('Trx Step')), - abort: jest.fn(), - }) - - const response = await graphql({ - schema, - source: ` - mutation { - removeOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('owner'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to remove organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx step error occurred for user: 123 while attempting to remove affiliations, and the org while removing org: 123, Error: Trx Step`, - ]) - }) - }) - }) - describe('given a trx commit error', () => { + describe('given a data source error', () => { it('throws an error', async () => { - const mockedCursor = { - all: jest.fn().mockReturnValueOnce([]).mockReturnValue([]), - } - - const mockedQuery = jest.fn().mockReturnValue(mockedCursor) - - const mockedTransaction = jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue({}), - commit: jest.fn().mockRejectedValue(new Error('Commit Error')), - abort: jest.fn(), - }) - const response = await graphql({ schema, source: ` @@ -3563,9 +2967,6 @@ describe('removing an organization', () => { rootValue: null, contextValue: { i18n, - query: mockedQuery, - collections: collectionNames, - transaction: mockedTransaction, userKey: 123, request: { ip: '127.0.0.1' }, auth: { @@ -3574,34 +2975,25 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - _key: 123, - verified: false, + dataSources: { + auditLogs: { logActivity: jest.fn() }, + organization: { + byKey: { + load: jest.fn().mockReturnValue({ + _id: 'organizations/123', + _key: '123', + verified: false, + slug: 'treasury-board-secretariat', + name: 'Treasury Board of Canada Secretariat', + }), + }, + getRawByKey: jest.fn().mockResolvedValue({ orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, + en: { name: 'Treasury Board of Canada Secretariat' }, + fr: { name: 'Secrétariat du Conseil Trésor du Canada' }, }, }), + remove: jest.fn().mockRejectedValue(new Error('Unable to remove organization. Please try again.')), }, }, }, @@ -3610,9 +3002,7 @@ describe('removing an organization', () => { const error = [new GraphQLError('Unable to remove organization. Please try again.')] expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Trx commit error occurred for user: 123 while attempting remove of org: 123, Error: Commit Error`, - ]) + expect(consoleOutput).toEqual([]) }) }) }) diff --git a/api/src/organization/mutations/__tests__/update-organization.test.js b/api/src/organization/mutations/__tests__/update-organization.test.js index 48d617201c..1a169220ba 100644 --- a/api/src/organization/mutations/__tests__/update-organization.test.js +++ b/api/src/organization/mutations/__tests__/update-organization.test.js @@ -1,7 +1,5 @@ import { setupI18n } from '@lingui/core' -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' +import { graphql, GraphQLSchema } from 'graphql' import { toGlobalId } from 'graphql-relay' import { createQuerySchema } from '../../../query' @@ -9,4165 +7,866 @@ import { createMutationSchema } from '../../../mutation' import englishMessages from '../../../locale/en/messages' import frenchMessages from '../../../locale/fr/messages' import { cleanseInput, slugify } from '../../../validators' -import { checkPermission, userRequired, verifiedRequired } from '../../../auth' -import { loadUserByKey } from '../../../user/loaders' -import { loadOrgByKey } from '../../loaders' -import dbschema from '../../../../database.json' -import { collectionNames } from '../../../collection-names' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('updating an organization', () => { - let query, drop, truncate, schema, collections, transaction, user +const ORG_KEY = 'org123' +const ORG_GID = toGlobalId('organization', ORG_KEY) + +const BASE_RAW_ORG = { + _id: `organizations/${ORG_KEY}`, + _key: ORG_KEY, + externalId: 'ext-001', + externallyManaged: false, + orgDetails: { + en: { + slug: 'treasury-board-secretariat', + acronym: 'TBS', + name: 'Treasury Board of Canada Secretariat', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + fr: { + slug: 'secretariat-conseil-tresor', + acronym: 'SCT', + name: 'Secrétariat du Conseil Trésor du Canada', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + }, + }, +} + +// Flat object returned by byKey.load after the update (language-resolved, as the Organization type expects). +// _type: 'organization' is required by updateOrganizationUnion resolveType. +const RESOLVED_ORG = { + _type: 'organization', + id: ORG_KEY, + _key: ORG_KEY, + _id: `organizations/${ORG_KEY}`, + acronym: 'TBS', + name: 'Treasury Board of Canada Secretariat', + slug: 'treasury-board-secretariat', + zone: 'FED', + sector: 'TBS', + country: 'Canada', + province: 'Ontario', + city: 'Ottawa', + verified: false, +} + +const BASE_USER = { _key: 'user123', userName: 'test@example.com' } + +describe('updateOrganization', () => { + let schema, enI18n, frI18n const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) + beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema + console.info = (o) => consoleOutput.push(o) + console.warn = (o) => consoleOutput.push(o) + console.error = (o) => consoleOutput.push(o) + schema = new GraphQLSchema({ query: createQuerySchema(), mutation: createMutationSchema(), }) + + enI18n = setupI18n({ + locale: 'en', + localeData: { en: { plurals: {} }, fr: { plurals: {} } }, + locales: ['en', 'fr'], + messages: { en: englishMessages.messages, fr: frenchMessages.messages }, + }) + + frI18n = setupI18n({ + locale: 'fr', + localeData: { en: { plurals: {} }, fr: { plurals: {} } }, + locales: ['en', 'fr'], + messages: { en: englishMessages.messages, fr: frenchMessages.messages }, + }) }) - beforeEach(() => { + + afterEach(() => { consoleOutput.length = 0 }) - describe('given a successful organization update', () => { - let org - beforeEach(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections, transaction } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - user = await collections.users.save({ - userName: 'test.account@istio.actually.exists', - emailValidated: true, - }) - org = await collections.organizations.save({ - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, + // Builds the organization data source mock. firstLoad is what byKey.load returns on the + // initial existence check; secondLoad is what it returns after the update + cache clear. + // Note: uses hasOwnProperty so callers can explicitly pass undefined (org not found). + function makeOrgDS(opts = {}) { + const firstLoad = Object.prototype.hasOwnProperty.call(opts, 'firstLoad') ? opts.firstLoad : BASE_RAW_ORG + const secondLoad = opts.secondLoad ?? RESOLVED_ORG + const nameInUseCount = opts.nameInUseCount ?? 0 + const rawOrg = opts.rawOrg ?? BASE_RAW_ORG + const update = opts.update ?? jest.fn() + const checkNameInUse = opts.checkNameInUse ?? null + const getRawByKey = opts.getRawByKey ?? null + + return { + byKey: { + load: jest.fn().mockResolvedValueOnce(firstLoad).mockResolvedValueOnce(secondLoad), + clear: jest.fn(), + }, + checkNameInUse: checkNameInUse ?? jest.fn().mockResolvedValue({ count: nameInUseCount }), + getRawByKey: getRawByKey ?? jest.fn().mockResolvedValue(rawOrg), + update, + } + } + + function makeContext({ + i18n = enI18n, + permission = 'admin', + orgDS = null, + logActivity = jest.fn(), + userKey = 'user123', + ip = '1.2.3.4', + } = {}) { + return { + i18n, + userKey, + request: { ip }, + auth: { + userRequired: jest.fn().mockReturnValue(BASE_USER), + verifiedRequired: jest.fn(), + checkPermission: jest.fn().mockReturnValue(permission), + }, + dataSources: { + auditLogs: { logActivity }, + organization: orgDS ?? makeOrgDS(), + }, + validators: { cleanseInput, slugify }, + } + } + + describe('given a successful update', () => { + it('returns the updated organization on success', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { + id: "${ORG_GID}" + nameEN: "New English Name" + nameFR: "Nouveau Nom Français" + acronymEN: "NEN" + acronymFR: "NNF" + }) { + result { + ... on Organization { id name acronym slug } + ... on OrganizationError { code description } + } + } + } + `, + contextValue: makeContext(), }) - }) - - afterEach(async () => { - await truncate() - await drop() - }) - describe('users permission level is super_admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'super_admin', - }) + expect(response.errors).toBeUndefined() + expect(response.data.updateOrganization.result).toMatchObject({ + name: RESOLVED_ORG.name, + acronym: RESOLVED_ORG.acronym, + slug: RESOLVED_ORG.slug, }) - describe('users language is english', () => { - describe('updating the acronym', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymEN: "TEST" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(consoleOutput).toContain(`User: user123, successfully updated org ${ORG_KEY}.`) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TEST', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + it('calls update with correctly merged org details', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the name', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - nameEN: "Test" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Updated Name" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Test', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, } + } + `, + contextValue: makeContext({ orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the zone', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - zoneEN: "New Zone" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(update).toHaveBeenCalledWith( + expect.objectContaining({ + orgKey: ORG_KEY, + updatedOrgDetails: expect.objectContaining({ + orgDetails: expect.objectContaining({ + en: expect.objectContaining({ name: 'Updated Name' }), + }), + }), + }), + ) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'New Zone', - }, - }, - }, - } + it('preserves existing fields when only partial inputs are provided', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the sector', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - sectorEN: "New Sector" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Only EN Updated" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'New Sector', - zone: 'FED', - }, - }, - }, } + } + `, + contextValue: makeContext({ orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the country', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - countryEN: "A New Country" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + const { updatedOrgDetails } = update.mock.calls[0][0] + expect(updatedOrgDetails.orgDetails.fr.name).toBe(BASE_RAW_ORG.orgDetails.fr.name) + expect(updatedOrgDetails.orgDetails.en.acronym).toBe(BASE_RAW_ORG.orgDetails.en.acronym) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'A New Country', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + it('clears byKey cache before reloading the organization', async () => { + const clear = jest.fn() + const orgDS = makeOrgDS() + orgDS.byKey.clear = clear - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the province', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - provinceEN: "A New Province" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Test" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'A New Province', - sector: 'TBS', - zone: 'FED', - }, - }, - }, } + } + `, + contextValue: makeContext({ orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the city', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(clear).toHaveBeenCalledWith(ORG_KEY) + }) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'A New City', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + describe('audit logging', () => { + it('logs audit activity when nameEN is changed', async () => { + const logActivity = jest.fn() - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating all organizational fields', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymEN: "NEW_ACRONYM" - nameEN: "New Name" - zoneEN: "New Zone" - sectorEN: "New Sector" - countryEN: "New Country" - provinceEN: "New Province" - cityEN: "New City" - acronymFR: "NOUVEL_ACRONYME" - nameFR: "Nouveau nom" - zoneFR: "Nouvelle zone" - sectorFR: "Nouveau secteur" - countryFR: "Nouveau pays" - provinceFR: "Nouvelle province" - cityFR: "Nouvelle ville" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Brand New Name" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'NEW_ACRONYM', - name: 'New Name', - zone: 'New Zone', - sector: 'New Sector', - country: 'New Country', - province: 'New Province', - city: 'New City', - }, - }, - }, } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) + } + `, + contextValue: makeContext({ logActivity }), }) - describe('users language is french', () => { - describe('updating the acronym', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymFR: "TEST" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TEST', - city: 'Ottawa', - country: 'Canada', - name: 'Secrétariat du Conseil Trésor du Canada', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + expect(logActivity).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'update', + target: expect.objectContaining({ + resourceType: 'organization', + updatedProperties: expect.arrayContaining([ + expect.objectContaining({ + name: 'nameEN', + oldValue: BASE_RAW_ORG.orgDetails.en.name, + newValue: 'Brand New Name', + }), + ]), + }), + }), + ) + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the name', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - nameFR: "Test" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + it('logs audit activity when nameFR is changed', async () => { + const logActivity = jest.fn() - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - city: 'Ottawa', - country: 'Canada', - name: 'Test', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameFR: "Nouveau Nom" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } + } } + } + `, + contextValue: makeContext({ logActivity }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the zone', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - zoneFR: "Secret Zone" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(logActivity).toHaveBeenCalledWith( + expect.objectContaining({ + target: expect.objectContaining({ + updatedProperties: expect.arrayContaining([ + expect.objectContaining({ name: 'nameFR', newValue: 'Nouveau Nom' }), + ]), + }), + }), + ) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'Secret Zone', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }, - } + it('logs audit activity when acronymEN is changed', async () => { + const logActivity = jest.fn() - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the sector', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - sectorFR: "New Sector" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" acronymEN: "NEW" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'New Sector', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }, } + } + `, + contextValue: makeContext({ logActivity }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the country', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - countryFR: "A New Country" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(logActivity).toHaveBeenCalledWith( + expect.objectContaining({ + target: expect.objectContaining({ + updatedProperties: expect.arrayContaining([ + expect.objectContaining({ name: 'acronymEN', newValue: 'NEW' }), + ]), + }), + }), + ) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'A New Country', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }, - } + it('logs audit activity when acronymFR is changed', async () => { + const logActivity = jest.fn() - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the province', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - provinceFR: "A New Province" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" acronymFR: "NVL" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'A New Province', - city: 'Ottawa', - }, - }, - }, } + } + `, + contextValue: makeContext({ logActivity }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the city', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - cityFR: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(logActivity).toHaveBeenCalledWith( + expect.objectContaining({ + target: expect.objectContaining({ + updatedProperties: expect.arrayContaining([ + expect.objectContaining({ name: 'acronymFR', newValue: 'NVL' }), + ]), + }), + }), + ) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - city: 'A New City', - country: 'Canada', - name: 'Secrétariat du Conseil Trésor du Canada', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + it('does not log when only zone/sector/location fields are updated', async () => { + const logActivity = jest.fn() - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating all organizational fields', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymEN: "NEW_ACRONYM" - nameEN: "New Name" - zoneEN: "New Zone" - sectorEN: "New Sector" - countryEN: "New Country" - provinceEN: "New Province" - cityEN: "New City" - acronymFR: "NOUVEL_ACRONYME" - nameFR: "Nouveau nom" - zoneFR: "Nouvelle zone" - sectorFR: "Nouveau secteur" - countryFR: "Nouveau pays" - provinceFR: "Nouvelle province" - cityFR: "Nouvelle ville" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" zoneEN: "NEWZONE" sectorEN: "NEWSECTOR" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'NOUVEL_ACRONYME', - city: 'Nouvelle ville', - country: 'Nouveau pays', - name: 'Nouveau nom', - province: 'Nouvelle province', - sector: 'Nouveau secteur', - zone: 'Nouvelle zone', - }, - }, - }, } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) + } + `, + contextValue: makeContext({ logActivity }), }) + + expect(logActivity).not.toHaveBeenCalled() }) - describe('users permission level is admin', () => { - beforeEach(async () => { - await collections.affiliations.save({ - _from: org._id, - _to: user._id, - permission: 'admin', - }) - }) - describe('users language is english', () => { - describe('updating the acronym', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymEN: "TEST" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TEST', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + it('populates initiatedBy with user key, userName, role, and IP address', async () => { + const logActivity = jest.fn() - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the name', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - nameEN: "Test" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Some Name" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Test', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, } + } + `, + contextValue: makeContext({ logActivity, ip: '10.0.0.1', permission: 'admin' }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the zone', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - zoneEN: "New Zone" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(logActivity).toHaveBeenCalledWith( + expect.objectContaining({ + initiatedBy: { + id: BASE_USER._key, + userName: BASE_USER.userName, + role: 'admin', + ipAddress: '10.0.0.1', + }, + }), + ) + }) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'New Zone', - }, - }, - }, - } + describe('super_admin exclusive fields', () => { + it('super_admin can set externallyManaged to true', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the sector', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - sectorEN: "New Sector" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" externallyManaged: true }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'New Sector', - zone: 'FED', - }, - }, - }, } + } + `, + contextValue: makeContext({ permission: 'super_admin', orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the country', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - countryEN: "A New Country" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(update).toHaveBeenCalledWith( + expect.objectContaining({ + updatedOrgDetails: expect.objectContaining({ externallyManaged: true }), + }), + ) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'A New Country', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + it('super_admin can set externallyManaged to false', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the province', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - provinceEN: "A New Province" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" externallyManaged: false }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'Ottawa', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'A New Province', - sector: 'TBS', - zone: 'FED', - }, - }, - }, } + } + `, + contextValue: makeContext({ permission: 'super_admin', orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the city', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(update).toHaveBeenCalledWith( + expect.objectContaining({ + updatedOrgDetails: expect.objectContaining({ externallyManaged: false }), + }), + ) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TBS', - city: 'A New City', - country: 'Canada', - name: 'Treasury Board of Canada Secretariat', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + it('admin cannot set externallyManaged — field is omitted from update payload', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating all organizational fields', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymEN: "NEW_ACRONYM" - nameEN: "New Name" - zoneEN: "New Zone" - sectorEN: "New Sector" - countryEN: "New Country" - provinceEN: "New Province" - cityEN: "New City" - acronymFR: "NOUVEL_ACRONYME" - nameFR: "Nouveau nom" - zoneFR: "Nouvelle zone" - sectorFR: "Nouveau secteur" - countryFR: "Nouveau pays" - provinceFR: "Nouvelle province" - cityFR: "Nouvelle ville" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" externallyManaged: true }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'en' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'NEW_ACRONYM', - name: 'New Name', - zone: 'New Zone', - sector: 'New Sector', - country: 'New Country', - province: 'New Province', - city: 'New City', - }, - }, - }, } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) + } + `, + contextValue: makeContext({ permission: 'admin', orgDS }), }) - describe('users language is french', () => { - describe('updating the acronym', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymFR: "TEST" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'TEST', - city: 'Ottawa', - country: 'Canada', - name: 'Secrétariat du Conseil Trésor du Canada', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + const { updatedOrgDetails } = update.mock.calls[0][0] + expect(updatedOrgDetails).not.toHaveProperty('externallyManaged') + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the name', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - nameFR: "Test" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + it('externallyManaged omitted from input is never set even for super_admin', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - city: 'Ottawa', - country: 'Canada', - name: 'Test', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "No Managed Field" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } + } } + } + `, + contextValue: makeContext({ permission: 'super_admin', orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the zone', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - zoneFR: "Secret Zone" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + const { updatedOrgDetails } = update.mock.calls[0][0] + expect(updatedOrgDetails).not.toHaveProperty('externallyManaged') + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'Secret Zone', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }, - } + it('super_admin can update externalId', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the sector', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - sectorFR: "New Sector" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" externalId: "new-ext-id" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'New Sector', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }, } + } + `, + contextValue: makeContext({ permission: 'super_admin', orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the country', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - countryFR: "A New Country" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + expect(update).toHaveBeenCalledWith( + expect.objectContaining({ + updatedOrgDetails: expect.objectContaining({ externalId: 'new-ext-id' }), + }), + ) + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'A New Country', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }, - } + it('admin cannot update externalId — field is omitted from update payload', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the province', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - provinceFR: "A New Province" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" externalId: "should-be-ignored" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'A New Province', - city: 'Ottawa', - }, - }, - }, } + } + `, + contextValue: makeContext({ permission: 'admin', orgDS }), + }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating the city', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - cityFR: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) + const { updatedOrgDetails } = update.mock.calls[0][0] + expect(updatedOrgDetails).not.toHaveProperty('externalId') + }) - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'SCT', - city: 'A New City', - country: 'Canada', - name: 'Secrétariat du Conseil Trésor du Canada', - province: 'Ontario', - sector: 'TBS', - zone: 'FED', - }, - }, - }, - } + it('super_admin falls back to existing externalId when none is provided', async () => { + const update = jest.fn() + const orgDS = makeOrgDS({ update }) - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) - describe('updating all organizational fields', () => { - it('returns the updated organization', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', org._key)}" - acronymEN: "NEW_ACRONYM" - nameEN: "New Name" - zoneEN: "New Zone" - sectorEN: "New Sector" - countryEN: "New Country" - provinceEN: "New Province" - cityEN: "New City" - acronymFR: "NOUVEL_ACRONYME" - nameFR: "Nouveau nom" - zoneFR: "Nouvelle zone" - sectorFR: "Nouveau secteur" - countryFR: "Nouveau pays" - provinceFR: "Nouvelle province" - cityFR: "Nouvelle ville" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Some Name" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - `, - rootValue: null, - contextValue: { - query, - collections: collectionNames, - transaction, - userKey: user._key, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: checkPermission({ - userKey: user._key, - query, - }), - userRequired: userRequired({ - userKey: user._key, - loadUserByKey: loadUserByKey({ query }), - }), - verifiedRequired: verifiedRequired({}), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: loadOrgByKey({ query, language: 'fr' }), - loadUserByKey: loadUserByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - updateOrganization: { - result: { - acronym: 'NOUVEL_ACRONYME', - city: 'Nouvelle ville', - country: 'Nouveau pays', - name: 'Nouveau nom', - province: 'Nouvelle province', - sector: 'Nouveau secteur', - zone: 'Nouvelle zone', - }, - }, - }, } - - expect(response).toEqual(expectedResponse) - expect(consoleOutput).toEqual([`User: ${user._key}, successfully updated org ${org._key}.`]) - }) - }) + } + `, + contextValue: makeContext({ permission: 'super_admin', orgDS }), }) + + const { updatedOrgDetails } = update.mock.calls[0][0] + expect(updatedOrgDetails.externalId).toBe(BASE_RAW_ORG.externalId) }) }) - describe('given an unsuccessful organization update', () => { - let i18n - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('organization cannot be found', () => { - describe('organization does not exist in database', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { id: "${toGlobalId('organization', 1)}", cityEN: "A New City" } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - const error = { - data: { - updateOrganization: { - result: { - code: 400, - description: 'Unable to update unknown organization.', - }, - }, - }, + describe('error: unknown organization', () => { + it('returns code 400 with correct message (EN) and logs a warning', async () => { + const orgDS = makeOrgDS({ firstLoad: undefined }) + + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Whatever" }) { + result { + ... on OrganizationError { code description } + ... on Organization { id } + } } + } + `, + contextValue: makeContext({ orgDS }), + }) - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to update organization: 1, however no organizations is associated with that id.`, - ]) - }) - }) + expect(response.errors).toBeUndefined() + expect(response.data.updateOrganization.result).toEqual({ + code: 400, + description: 'Unable to update unknown organization.', }) - describe('user is located in the database', () => { - describe('user does not have the proper permissions', () => { - describe('user has user level permission', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', 123)}" - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('user'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _id: 'organizations/123' }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) + expect(consoleOutput).toContain( + `User: user123 attempted to update organization: ${ORG_KEY}, however no organizations is associated with that id.`, + ) + }) + + it('returns a translated 400 error (FR)', async () => { + const orgDS = makeOrgDS({ firstLoad: undefined }) - const error = { - data: { - updateOrganization: { - result: { - code: 403, - description: - 'Permission Denied: Please contact organization admin for help with updating organization.', - }, - }, - }, + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Whatever" }) { + result { + ... on OrganizationError { code description } + ... on Organization { id } } + } + } + `, + contextValue: makeContext({ i18n: frI18n, orgDS }), + }) - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to update organization 123, however they do not have the correct permission level. Permission: user`, - ]) - }) - }) - describe('user does not belong to that organization', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', 123)}" - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue(undefined), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _id: 'organizations/123' }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) + expect(response.data.updateOrganization.result.code).toBe(400) + expect(response.data.updateOrganization.result.description).not.toBe('Unable to update unknown organization.') + }) + }) - const error = { - data: { - updateOrganization: { - result: { - code: 403, - description: - 'Permission Denied: Please contact organization admin for help with updating organization.', - }, - }, - }, + describe('error: insufficient permission', () => { + it('returns code 403 with correct message for user role (EN) and logs an error', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Whatever" }) { + result { + ... on OrganizationError { code description } + ... on Organization { id } } + } + } + `, + contextValue: makeContext({ permission: 'user' }), + }) - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to update organization 123, however they do not have the correct permission level. Permission: undefined`, - ]) - }) - }) - }) + expect(response.errors).toBeUndefined() + expect(response.data.updateOrganization.result).toEqual({ + code: 403, + description: 'Permission Denied: Please contact organization admin for help with updating organization.', }) - describe('organization name is already in use', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - nameEN: "Treasury Board of Canada Secretariat" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ count: 1 }), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) + expect(consoleOutput).toContain( + `User: user123 attempted to update organization ${ORG_KEY}, however they do not have the correct permission level. Permission: user`, + ) + }) - const error = { - data: { - updateOrganization: { - result: { - code: 400, - description: 'Organization name already in use, please choose another and try again.', - }, - }, - }, + it('returns a translated 403 error for user role (FR)', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Whatever" }) { + result { + ... on OrganizationError { code description } + ... on Organization { id } + } + } } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to change the name of org: 123 however it is already in use.`, - ]) - }) + `, + contextValue: makeContext({ i18n: frI18n, permission: 'user' }), }) - describe('cursor error occurs', () => { - describe('when gathering comparison org details', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - next() { - throw new Error('Database error occurred.') - }, - }), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - const error = [new GraphQLError('Unable to update organization. Please try again.')] + expect(response.data.updateOrganization.result.code).toBe(403) + expect(response.data.updateOrganization.result.description).not.toBe( + 'Permission Denied: Please contact organization admin for help with updating organization.', + ) + }) - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred while retrieving org: 123 for update, err: Error: Database error occurred.`, - ]) - }) - }) + it('returns code 403 for undefined permission (no org affiliation)', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Whatever" }) { + result { + ... on OrganizationError { code description } + ... on Organization { id } + } + } + } + `, + contextValue: makeContext({ permission: null }), }) - describe('database error occurs', () => { - describe('when gathering comparison org details', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to update organization. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred while retrieving org: 123 for update, err: Error: Database error occurred.`, - ]) - }) - }) - describe('when checking to see if orgName is already in use', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - nameEN: "Treasury Board of Canada Secretariat" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) + expect(response.data.updateOrganization.result.code).toBe(403) + }) + }) - const error = [new GraphQLError('Unable to update organization. Please try again.')] + describe('error: organization name already in use', () => { + it('returns code 400 with correct message (EN) and logs an error', async () => { + const orgDS = makeOrgDS({ nameInUseCount: 1 }) - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred during name check when user: 123 attempted to update org: 123, Error: Database error occurred.`, - ]) - }) - }) + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Taken Name" }) { + result { + ... on OrganizationError { code description } + ... on Organization { id } + } + } + } + `, + contextValue: makeContext({ orgDS }), }) - describe('transaction error occurs', () => { - describe('when updating/inserting new org details', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue({ - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to update organization. Please try again.')] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred while upserting org: 123, err: Error: trx step error`, - ]) - }) - }) - describe('when committing transaction', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue({ - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to update organization. Please try again.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred while committing org: 123, err: Error: trx commit error`, - ]) - }) - }) + expect(response.errors).toBeUndefined() + expect(response.data.updateOrganization.result).toEqual({ + code: 400, + description: 'Organization name already in use, please choose another and try again.', }) + expect(consoleOutput).toContain( + `User: user123 attempted to change the name of org: ${ORG_KEY} however it is already in use.`, + ) }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('organization cannot be found', () => { - describe('organization does not exist in database', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { id: "${toGlobalId('organization', 1)}", cityEN: "A New City" } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - const error = { - data: { - updateOrganization: { - result: { - code: 400, - description: 'Impossible de mettre à jour une organisation inconnue.', - }, - }, - }, - } + it('returns a translated 400 error when name conflicts (FR)', async () => { + const orgDS = makeOrgDS({ nameInUseCount: 1 }) - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to update organization: 1, however no organizations is associated with that id.`, - ]) - }) - }) + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Taken Name" }) { + result { + ... on OrganizationError { code description } + ... on Organization { id } + } + } + } + `, + contextValue: makeContext({ i18n: frI18n, orgDS }), }) - describe('user is located in the database', () => { - describe('user does not have the proper permissions', () => { - describe('user has user level permission', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', 123)}" - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('user'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _id: 'organizations/123' }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - const error = { - data: { - updateOrganization: { - result: { - code: 403, - description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la suppression des utilisateurs.", - }, - }, - }, - } + expect(response.data.updateOrganization.result.code).toBe(400) + expect(response.data.updateOrganization.result.description).not.toBe( + 'Organization name already in use, please choose another and try again.', + ) + }) - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to update organization 123, however they do not have the correct permission level. Permission: user`, - ]) - }) - }) - describe('user does not belong to that organization', () => { - it('returns an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization ( - input: { - id: "${toGlobalId('organization', 123)}" - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue(undefined), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ _id: 'organizations/123' }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) + it('skips the name check when neither nameEN nor nameFR is provided', async () => { + const checkNameInUse = jest.fn() + const orgDS = makeOrgDS({ checkNameInUse }) - const error = { - data: { - updateOrganization: { - result: { - code: 403, - description: - "Permission refusée : Veuillez contacter l'administrateur de l'organisation pour obtenir de l'aide sur la suppression des utilisateurs.", - }, - }, - }, + await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" zoneEN: "NewZone" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to update organization 123, however they do not have the correct permission level. Permission: undefined`, - ]) - }) - }) - }) - }) - describe('organization name is already in use', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - nameEN: "Treasury Board of Canada Secretariat" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ count: 1 }), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - - const error = { - data: { - updateOrganization: { - result: { - code: 400, - description: "Le nom de l'organisation est déjà utilisé, veuillez en choisir un autre et réessayer.", - }, - }, - }, + } } - - expect(response).toEqual(error) - expect(consoleOutput).toEqual([ - `User: 123 attempted to change the name of org: 123 however it is already in use.`, - ]) - }) + `, + contextValue: makeContext({ orgDS }), }) - describe('cursor error occurs', () => { - describe('when gathering comparison org details', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - next() { - throw new Error('Database error occurred.') - }, - }), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - const error = [new GraphQLError("Impossible de mettre à jour l'organisation. Veuillez réessayer.")] + expect(checkNameInUse).not.toHaveBeenCalled() + }) + }) - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Cursor error occurred while retrieving org: 123 for update, err: Error: Database error occurred.`, - ]) - }) - }) + describe('error: data source failures', () => { + it('propagates error thrown by organizationDS.update', async () => { + const orgDS = makeOrgDS({ + update: jest.fn().mockRejectedValue(new Error('Unable to load organization. Please try again.')), }) - describe('database error occurs', () => { - describe('when gathering comparison org details', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - - const error = [new GraphQLError("Impossible de mettre à jour l'organisation. Veuillez réessayer.")] - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred while retrieving org: 123 for update, err: Error: Database error occurred.`, - ]) - }) - }) - describe('when checking to see if orgName is already in use', () => { - it('throws an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - nameEN: "Treasury Board of Canada Secretariat" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockRejectedValue(new Error('Database error occurred.')), - collections: collectionNames, - transaction, - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Fail Update" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } + } + } + } + `, + contextValue: makeContext({ orgDS }), + }) - const error = [new GraphQLError("Impossible de mettre à jour l'organisation. Veuillez réessayer.")] + expect(response.errors).toBeDefined() + expect(response.errors[0].message).toBe('Unable to load organization. Please try again.') + }) - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Database error occurred during name check when user: 123 attempted to update org: 123, Error: Database error occurred.`, - ]) - }) - }) + it('propagates error thrown by organizationDS.checkNameInUse', async () => { + const orgDS = makeOrgDS({ + checkNameInUse: jest.fn().mockRejectedValue(new Error('Unable to update organization. Please try again.')), }) - describe('transaction error occurs', () => { - describe('when updating/inserting new org details', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue({ - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) - const error = [new GraphQLError("Impossible de mettre à jour l'organisation. Veuillez réessayer.")] + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" nameEN: "Fail Check" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } + } + } + } + `, + contextValue: makeContext({ orgDS }), + }) - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred while upserting org: 123, err: Error: trx step error`, - ]) - }) - }) - describe('when committing transaction', () => { - it('returns an error', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - updateOrganization( - input: { - id: "${toGlobalId('organization', 123)}", - cityEN: "A New City" - } - ) { - result { - ... on Organization { - acronym - name - zone - sector - country - province - city - } - ... on OrganizationError { - code - description - } - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - query: jest.fn().mockReturnValue({ - next: jest.fn().mockReturnValue({ - orgDetails: { - en: { - slug: 'treasury-board-secretariat', - acronym: 'TBS', - name: 'Treasury Board of Canada Secretariat', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - fr: { - slug: 'secretariat-conseil-tresor', - acronym: 'SCT', - name: 'Secrétariat du Conseil Trésor du Canada', - zone: 'FED', - sector: 'TBS', - country: 'Canada', - province: 'Ontario', - city: 'Ottawa', - }, - }, - }), - }), - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn(), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }), - userKey: 123, - request: { ip: '127.0.0.1' }, - auth: { - checkPermission: jest.fn().mockReturnValue('admin'), - userRequired: jest.fn().mockReturnValue({ _key: 123 }), - verifiedRequired: jest.fn(), - }, - validators: { - cleanseInput, - slugify, - }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - name: 'Treasury Board of Canada Secretariat', - _key: 123, - }), - }, - loadUserByKey: { - load: jest.fn(), - }, - }, - }, - }) + expect(response.errors).toBeDefined() + expect(response.errors[0].message).toBe('Unable to update organization. Please try again.') + }) - const error = [new GraphQLError("Impossible de mettre à jour l'organisation. Veuillez réessayer.")] + it('propagates error thrown by organizationDS.getRawByKey', async () => { + const orgDS = makeOrgDS({ + getRawByKey: jest.fn().mockRejectedValue(new Error('Unable to load organization. Please try again.')), + }) - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([ - `Transaction error occurred while committing org: 123, err: Error: trx commit error`, - ]) - }) - }) + const response = await graphql({ + schema, + source: ` + mutation { + updateOrganization(input: { id: "${ORG_GID}" zoneEN: "FED" }) { + result { + ... on Organization { id } + ... on OrganizationError { code description } + } + } + } + `, + contextValue: makeContext({ orgDS }), }) + + expect(response.errors).toBeDefined() + expect(response.errors[0].message).toBe('Unable to load organization. Please try again.') }) }) }) diff --git a/api/src/organization/mutations/__tests__/verify-organization.test.js b/api/src/organization/mutations/__tests__/verify-organization.test.js index b70f6f3cc0..86a37edfa5 100644 --- a/api/src/organization/mutations/__tests__/verify-organization.test.js +++ b/api/src/organization/mutations/__tests__/verify-organization.test.js @@ -11,8 +11,8 @@ import frenchMessages from '../../../locale/fr/messages' import { cleanseInput } from '../../../validators' import { checkPermission, userRequired, verifiedRequired } from '../../../auth' import { loadUserByKey } from '../../../user/loaders' -import { loadOrgByKey } from '../../loaders' import { loadDomainByKey } from '../../../domain/loaders' +import { OrganizationDataSource } from '../../data-source' import dbschema from '../../../../database.json' import { collectionNames } from '../../../collection-names' @@ -172,13 +172,18 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: loadOrgByKey({ + dataSources: { + organization: new OrganizationDataSource({ query, - language: 'en', userKey: user._key, i18n, + language: 'en', + cleanseInput, + transaction, + collections: collectionNames, }), + }, + loaders: { loadUserByKey: loadUserByKey({ query, userKey: user._key, @@ -204,13 +209,8 @@ describe('removing an organization', () => { expect(response).toEqual(expectedResponse) expect(consoleOutput).toEqual([`User: ${user._key}, successfully verified org: ${org._key}.`]) - const orgLoader = loadOrgByKey({ - query, - language: 'en', - userKey: user._key, - i18n, - }) - const verifiedOrg = await orgLoader.load(org._key) + const orgDS = new OrganizationDataSource({ query, userKey: user._key, i18n, language: 'en', cleanseInput, transaction, collections: collectionNames }) + const verifiedOrg = await orgDS.byKey.load(org._key) expect(verifiedOrg.verified).toEqual(true) const domainLoader = loadDomainByKey({ query, userKey: user._key, i18n }) @@ -286,13 +286,18 @@ describe('removing an organization', () => { verifiedRequired: verifiedRequired({}), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: loadOrgByKey({ + dataSources: { + organization: new OrganizationDataSource({ query, - language: 'fr', userKey: user._key, i18n, + language: 'fr', + cleanseInput, + transaction, + collections: collectionNames, }), + }, + loaders: { loadUserByKey: loadUserByKey({ query, userKey: user._key, @@ -318,13 +323,8 @@ describe('removing an organization', () => { expect(response).toEqual(expectedResponse) expect(consoleOutput).toEqual([`User: ${user._key}, successfully verified org: ${org._key}.`]) - const orgLoader = loadOrgByKey({ - query, - language: 'fr', - userKey: user._key, - i18n, - }) - const verifiedOrg = await orgLoader.load(org._key) + const orgDS = new OrganizationDataSource({ query, userKey: user._key, i18n, language: 'fr', cleanseInput, transaction, collections: collectionNames }) + const verifiedOrg = await orgDS.byKey.load(org._key) expect(verifiedOrg.verified).toEqual(true) }) }) @@ -385,11 +385,9 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue(undefined), - }, - }, + } } }, }, }) @@ -450,13 +448,11 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _id: 'organizations/123', }), - }, - }, + } } }, }, }) @@ -517,13 +513,11 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _id: 'organizations/123', }), - }, - }, + } } }, }, }) @@ -585,13 +579,11 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ verified: true, }), - }, - }, + } } }, }, }) @@ -612,192 +604,55 @@ describe('removing an organization', () => { ]) }) }) - describe('transaction error occurs', () => { - describe('when stepping transaction', () => { - describe('when upserting org information', () => { - it('throws an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } + describe('data source error occurs', () => { + it('throws an error message', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + verifyOrganization( + input: { + orgId: "${toGlobalId('organization', 123)}" } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('super_admin'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to verify organization. Please try again.')] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - `Transaction error occurred while upserting verified org: 123, err: Error: trx step error`, - ]) - }) - }) - describe('when clearing owners', () => { - it('throws an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } + ) { + result { + ... on OrganizationResult { + status + organization { + name } } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('super_admin'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - }), - }, - }, - }, - }) - - const error = [new GraphQLError('Unable to verify organization. Please try again.')] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - `Transaction error occurred while upserting verified org: 123, err: Error: trx step error`, - ]) - }) - }) - }) - describe('when committing transaction', () => { - it('throws an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } + ... on OrganizationError { + code + description } } } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue(), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('super_admin'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - }), - }, + } + `, + rootValue: null, + contextValue: { + i18n, + userKey: 123, + auth: { + checkPermission: jest.fn().mockReturnValue('super_admin'), + userRequired: jest.fn(), + verifiedRequired: jest.fn(), + }, + validators: { cleanseInput }, + dataSources: { + organization: { + byKey: { load: jest.fn().mockReturnValue({ verified: false, _key: 123 }) }, + verify: jest.fn().mockRejectedValue(new Error('Unable to verify organization. Please try again.')), }, }, - }) - - const error = [new GraphQLError('Unable to verify organization. Please try again.')] + }, + }) - expect(response.errors).toEqual(error) + const error = [new GraphQLError('Unable to verify organization. Please try again.')] - expect(consoleOutput).toEqual([ - `Transaction error occurred while committing newly verified org: 123, err: Error: trx commit error`, - ]) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([]) }) }) }) @@ -855,11 +710,9 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue(undefined), - }, - }, + } } }, }, }) @@ -920,13 +773,11 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _id: 'organizations/123', }), - }, - }, + } } }, }, }) @@ -987,13 +838,11 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ _id: 'organizations/123', }), - }, - }, + } } }, }, }) @@ -1055,13 +904,11 @@ describe('removing an organization', () => { verifiedRequired: jest.fn(), }, validators: { cleanseInput }, - loaders: { - loadOrgByKey: { + dataSources: { organization: { byKey: { load: jest.fn().mockReturnValue({ verified: true, }), - }, - }, + } } }, }, }) @@ -1082,192 +929,55 @@ describe('removing an organization', () => { ]) }) }) - describe('transaction error occurs', () => { - describe('when stepping transaction', () => { - describe('when upserting org information', () => { - it('throws an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } - } - } + describe('data source error occurs', () => { + it('throws an error message', async () => { + const response = await graphql({ + schema, + source: ` + mutation { + verifyOrganization( + input: { + orgId: "${toGlobalId('organization', 123)}" } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('super_admin'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - }), - }, - }, - }, - }) - - const error = [new GraphQLError("Impossible de vérifier l'organisation. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - `Transaction error occurred while upserting verified org: 123, err: Error: trx step error`, - ]) - }) - }) - describe('when clearing owners', () => { - it('throws an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } + ) { + result { + ... on OrganizationResult { + status + organization { + name } } - } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockRejectedValue(new Error('trx step error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('super_admin'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - }), - }, - }, - }, - }) - - const error = [new GraphQLError("Impossible de vérifier l'organisation. Veuillez réessayer.")] - - expect(response.errors).toEqual(error) - - expect(consoleOutput).toEqual([ - `Transaction error occurred while upserting verified org: 123, err: Error: trx step error`, - ]) - }) - }) - }) - describe('when committing transaction', () => { - it('throws an error message', async () => { - const response = await graphql({ - schema, - source: ` - mutation { - verifyOrganization( - input: { - orgId: "${toGlobalId('organization', 123)}" - } - ) { - result { - ... on OrganizationResult { - status - organization { - name - } - } - ... on OrganizationError { - code - description - } + ... on OrganizationError { + code + description } } } - `, - rootValue: null, - contextValue: { - i18n, - query, - collections: collectionNames, - transaction: jest.fn().mockReturnValue({ - step: jest.fn().mockReturnValue(), - commit: jest.fn().mockRejectedValue(new Error('trx commit error')), - abort: jest.fn(), - }), - userKey: 123, - auth: { - checkPermission: jest.fn().mockReturnValue('super_admin'), - userRequired: jest.fn(), - verifiedRequired: jest.fn(), - }, - validators: { cleanseInput }, - loaders: { - loadOrgByKey: { - load: jest.fn().mockReturnValue({ - verified: false, - }), - }, + } + `, + rootValue: null, + contextValue: { + i18n, + userKey: 123, + auth: { + checkPermission: jest.fn().mockReturnValue('super_admin'), + userRequired: jest.fn(), + verifiedRequired: jest.fn(), + }, + validators: { cleanseInput }, + dataSources: { + organization: { + byKey: { load: jest.fn().mockReturnValue({ verified: false, _key: 123 }) }, + verify: jest.fn().mockRejectedValue(new Error("Impossible de vérifier l'organisation. Veuillez réessayer.")), }, }, - }) - - const error = [new GraphQLError("Impossible de vérifier l'organisation. Veuillez réessayer.")] + }, + }) - expect(response.errors).toEqual(error) + const error = [new GraphQLError("Impossible de vérifier l'organisation. Veuillez réessayer.")] - expect(consoleOutput).toEqual([ - `Transaction error occurred while committing newly verified org: 123, err: Error: trx commit error`, - ]) - }) + expect(response.errors).toEqual(error) + expect(consoleOutput).toEqual([]) }) }) }) diff --git a/api/src/organization/mutations/archive-organization.js b/api/src/organization/mutations/archive-organization.js index edb7e51fd6..583fa0de54 100644 --- a/api/src/organization/mutations/archive-organization.js +++ b/api/src/organization/mutations/archive-organization.js @@ -3,7 +3,7 @@ import { mutationWithClientMutationId, fromGlobalId } from 'graphql-relay' import { t } from '@lingui/macro' import { removeOrganizationUnion } from '../unions' -import { logActivity } from '../../audit-logs/mutations/log-activity' +import ac from '../../access-control' export const archiveOrganization = new mutationWithClientMutationId({ name: 'ArchiveOrganization', @@ -25,14 +25,11 @@ export const archiveOrganization = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, userKey, request: { ip }, auth: { checkPermission, userRequired, verifiedRequired }, validators: { cleanseInput }, - loaders: { loadOrgByKey }, + dataSources: { auditLogs, organization: organizationDS }, }, ) => { // Get user @@ -44,7 +41,7 @@ export const archiveOrganization = new mutationWithClientMutationId({ const { type: _orgType, id: orgId } = fromGlobalId(cleanseInput(args.orgId)) // Get org from db - const organization = await loadOrgByKey.load(orgId) + const organization = await organizationDS.byKey.load(orgId) // Check to see if org exists if (!organization) { @@ -59,7 +56,7 @@ export const archiveOrganization = new mutationWithClientMutationId({ // Get users permission const permission = await checkPermission({ orgId: organization._id }) - if (permission !== 'super_admin') { + if (!ac.can(permission).deleteAny('organization').granted) { console.warn( `User: ${userKey} attempted to archive org: ${organization._key}, however they do not have the correct permission level. Permission: ${permission}`, ) @@ -70,103 +67,11 @@ export const archiveOrganization = new mutationWithClientMutationId({ } } - // Setup Trans action - const trx = await transaction(collections) - - // check to see if any other orgs are using this domain - let countCursor - try { - countCursor = await query` - WITH claims, domains, organizations - LET domainIds = ( - FOR v, e IN 1..1 OUTBOUND ${organization._id} claims - RETURN e._to - ) - FOR domain IN domains - FILTER domain._id IN domainIds - LET count = LENGTH( - FOR v, e IN 1..1 INBOUND domain._id claims - RETURN 1 - ) - RETURN { - _id: domain._id, - _key: domain._key, - domain: domain.domain, - count - } - ` - } catch (err) { - console.error( - `Database error occurred for user: ${userKey} while attempting to gather domain count while archiving org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to archive organization. Please try again.`)) - } - - let domainInfo - try { - domainInfo = await countCursor.all() - } catch (err) { - console.error( - `Cursor error occurred for user: ${userKey} while attempting to gather domain count while archiving org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to archive organization. Please try again.`)) - } - - for (const domain of domainInfo) { - if (domain.count === 1) { - try { - // Archive domain - await trx.step( - async () => - await query` - WITH domains - UPDATE { _key: ${domain._key}, archived: true } IN domains - `, - ) - } catch (err) { - console.error( - `Trx step error occurred for user: ${userKey} while attempting to archive domains while archiving org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to archive organization. Please try again.`)) - } - } - } - - try { - await trx.step( - () => - query` - WITH organizations - UPDATE { _key: ${organization._key}, verified: false } IN organizations - `, - ) - } catch (err) { - console.error( - `Trx step error occurred for user: ${userKey} while attempting to unverify while archiving org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to archive organization. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error( - `Trx commit error occurred for user: ${userKey} while attempting archive of org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to archive organization. Please try again.`)) - } + await organizationDS.archive({ organization }) console.info(`User: ${userKey} successfully archived org: ${organization._key}.`) - await logActivity({ - transaction, - collections, - query, + await auditLogs.logActivity({ initiatedBy: { id: user._key, userName: user.userName, @@ -185,8 +90,8 @@ export const archiveOrganization = new mutationWithClientMutationId({ resource: { en: organization.name, fr: organization.name, - }, // name of resource being acted upon - resourceType: 'organization', // user, org, domain + }, + resourceType: 'organization', }, }) diff --git a/api/src/organization/mutations/create-organization.js b/api/src/organization/mutations/create-organization.js index 3af01f42cf..10c2d638e4 100644 --- a/api/src/organization/mutations/create-organization.js +++ b/api/src/organization/mutations/create-organization.js @@ -1,10 +1,9 @@ -import { GraphQLNonNull, GraphQLString } from 'graphql' +import { GraphQLNonNull, GraphQLString, GraphQLBoolean } from 'graphql' import { mutationWithClientMutationId } from 'graphql-relay' import { t } from '@lingui/macro' import { Acronym } from '../../scalars' import { createOrganizationUnion } from '../unions' -import { logActivity } from '../../audit-logs/mutations/log-activity' export const createOrganization = new mutationWithClientMutationId({ name: 'CreateOrganization', @@ -26,45 +25,13 @@ export const createOrganization = new mutationWithClientMutationId({ type: new GraphQLNonNull(GraphQLString), description: 'The French name of the organization.', }, - zoneEN: { - type: new GraphQLNonNull(GraphQLString), - description: 'The English translation of the zone the organization belongs to.', - }, - zoneFR: { - type: new GraphQLNonNull(GraphQLString), - description: 'The English translation of the zone the organization belongs to.', - }, - sectorEN: { - type: new GraphQLNonNull(GraphQLString), - description: 'The English translation of the sector the organization belongs to.', - }, - sectorFR: { - type: new GraphQLNonNull(GraphQLString), - description: 'The French translation of the sector the organization belongs to.', - }, - countryEN: { - type: new GraphQLNonNull(GraphQLString), - description: 'The English translation of the country the organization resides in.', - }, - countryFR: { - type: new GraphQLNonNull(GraphQLString), - description: 'The French translation of the country the organization resides in.', - }, - provinceEN: { - type: new GraphQLNonNull(GraphQLString), - description: 'The English translation of the province the organization resides in.', - }, - provinceFR: { - type: new GraphQLNonNull(GraphQLString), - description: 'The French translation of the province the organization resides in.', - }, - cityEN: { - type: new GraphQLNonNull(GraphQLString), - description: 'The English translation of the city the organization resides in.', + externalId: { + type: GraphQLString, + description: 'String ID used to identify the organization in an external system.', }, - cityFR: { - type: new GraphQLNonNull(GraphQLString), - description: 'The French translation of the city the organization resides in.', + verified: { + type: GraphQLBoolean, + description: 'If the organization is verified.', }, }), outputFields: () => ({ @@ -79,13 +46,10 @@ export const createOrganization = new mutationWithClientMutationId({ { i18n, request, - collections, - transaction, - query, userKey, request: { ip }, - auth: { userRequired, verifiedRequired }, - loaders: { loadOrgBySlug }, + auth: { userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired }, + dataSources: { auditLogs, organization: organizationDS }, validators: { cleanseInput, slugify }, }, ) => { @@ -93,29 +57,25 @@ export const createOrganization = new mutationWithClientMutationId({ const user = await userRequired() verifiedRequired({ user }) + const isSuperAdmin = await checkSuperAdmin() + + if (args.verified === true) { + superAdminRequired({ user, isSuperAdmin }) + } // Cleanse Input const acronymEN = cleanseInput(args.acronymEN) const acronymFR = cleanseInput(args.acronymFR) const nameEN = cleanseInput(args.nameEN) const nameFR = cleanseInput(args.nameFR) - const zoneEN = cleanseInput(args.zoneEN) - const zoneFR = cleanseInput(args.zoneFR) - const sectorEN = cleanseInput(args.sectorEN) - const sectorFR = cleanseInput(args.sectorFR) - const countryEN = cleanseInput(args.countryEN) - const countryFR = cleanseInput(args.countryFR) - const provinceEN = cleanseInput(args.provinceEN) - const provinceFR = cleanseInput(args.provinceFR) - const cityEN = cleanseInput(args.cityEN) - const cityFR = cleanseInput(args.cityFR) + const externalId = cleanseInput(args.externalId) // Create EN and FR slugs const slugEN = slugify(nameEN) const slugFR = slugify(nameFR) // Check to see if org already exists - const [orgEN, orgFR] = await loadOrgBySlug.loadMany([slugEN, slugFR]) + const [orgEN, orgFR] = await organizationDS.bySlug.loadMany([slugEN, slugFR]) if (typeof orgEN !== 'undefined' || typeof orgFR !== 'undefined') { console.warn(`User: ${userKey} attempted to create an organization that already exists: ${slugEN}`) @@ -126,101 +86,32 @@ export const createOrganization = new mutationWithClientMutationId({ } } - // Create new organization const organizationDetails = { - verified: false, + verified: args.verified || false, externallyManaged: false, + externalId, orgDetails: { en: { slug: slugEN, acronym: acronymEN, name: nameEN, - zone: zoneEN, - sector: sectorEN, - country: countryEN, - province: provinceEN, - city: cityEN, }, fr: { slug: slugFR, acronym: acronymFR, name: nameFR, - zone: zoneFR, - sector: sectorFR, - country: countryFR, - province: provinceFR, - city: cityFR, }, }, } - // Setup Trans action - const trx = await transaction(collections) - - let cursor - try { - cursor = await trx.step( - () => - query` - WITH organizations - INSERT ${organizationDetails} INTO organizations - RETURN MERGE( - { - _id: NEW._id, - _key: NEW._key, - _rev: NEW._rev, - _type: "organization", - id: NEW._key, - verified: NEW.verified, - domainCount: 0, - summaries: NEW.summaries - }, - TRANSLATE(${request.language}, NEW.orgDetails) - ) - `, - ) - } catch (err) { - console.error(`Transaction error occurred when user: ${userKey} was creating new organization ${slugEN}: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to create organization. Please try again.`)) - } - const organization = await cursor.next() - - try { - await trx.step( - () => - query` - WITH affiliations, organizations, users - INSERT { - _from: ${organization._id}, - _to: ${user._id}, - permission: "owner", - } INTO affiliations - `, - ) - } catch (err) { - console.error( - `Transaction error occurred when inserting edge definition for user: ${userKey} to ${slugEN}: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to create organization. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error( - `Transaction error occurred when committing new organization: ${slugEN} for user: ${userKey} to db: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to create organization. Please try again.`)) - } + const organization = await organizationDS.create({ + organizationDetails, + userId: user._id, + language: request.language, + }) console.info(`User: ${userKey} successfully created a new organization: ${slugEN}`) - await logActivity({ - transaction, - collections, - query, + await auditLogs.logActivity({ initiatedBy: { id: user._key, userName: user.userName, @@ -231,8 +122,8 @@ export const createOrganization = new mutationWithClientMutationId({ resource: { en: organizationDetails.orgDetails.en.name, fr: organizationDetails.orgDetails.fr.name, - }, // name of resource being acted upon - resourceType: 'organization', // user, org, domain + }, + resourceType: 'organization', }, }) diff --git a/api/src/organization/mutations/remove-organization.js b/api/src/organization/mutations/remove-organization.js index 0721de84d1..114566b58b 100644 --- a/api/src/organization/mutations/remove-organization.js +++ b/api/src/organization/mutations/remove-organization.js @@ -3,7 +3,7 @@ import { mutationWithClientMutationId, fromGlobalId } from 'graphql-relay' import { t } from '@lingui/macro' import { removeOrganizationUnion } from '../unions' -import { logActivity } from '../../audit-logs/mutations/log-activity' +import ac from '../../access-control' export const removeOrganization = new mutationWithClientMutationId({ name: 'RemoveOrganization', @@ -25,14 +25,11 @@ export const removeOrganization = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, userKey, request: { ip }, auth: { checkPermission, userRequired, verifiedRequired }, validators: { cleanseInput }, - loaders: { loadOrgByKey }, + dataSources: { auditLogs, organization: organizationDS }, }, ) => { // Get user @@ -44,7 +41,7 @@ export const removeOrganization = new mutationWithClientMutationId({ const { type: _orgType, id: orgId } = fromGlobalId(cleanseInput(args.orgId)) // Get org from db - const organization = await loadOrgByKey.load(orgId) + const organization = await organizationDS.byKey.load(orgId) // Check to see if org exists if (!organization) { @@ -59,7 +56,7 @@ export const removeOrganization = new mutationWithClientMutationId({ // Get users permission const permission = await checkPermission({ orgId: organization._id }) - if (['owner', 'super_admin'].includes(permission) === false) { + if (!ac.can(permission).deleteOwn('organization').granted) { console.warn( `User: ${userKey} attempted to remove org: ${organization._key}, however the user does not have permission to this organization.`, ) @@ -73,7 +70,7 @@ export const removeOrganization = new mutationWithClientMutationId({ } // Check to see if org is verified check, and the user is super admin - if (organization.verified && permission !== 'super_admin') { + if (organization.verified && !ac.can(permission).deleteAny('organization').granted) { console.warn( `User: ${userKey} attempted to remove org: ${organization._key}, however the user is not a super admin.`, ) @@ -84,319 +81,11 @@ export const removeOrganization = new mutationWithClientMutationId({ } } - // Setup Trans action - const trx = await transaction(collections) - - // check to see if org has any dmarc summaries - let dmarcSummaryCheckCursor - try { - dmarcSummaryCheckCursor = await query` - WITH domains, ownership, dmarcSummaries, organizations - FOR v, e IN 1..1 OUTBOUND ${organization._id} ownership - RETURN e - ` - } catch (err) { - console.error( - `Database error occurred for user: ${userKey} while attempting to get dmarcSummaryInfo while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - let dmarcSummaryCheckList - try { - dmarcSummaryCheckList = await dmarcSummaryCheckCursor.all() - } catch (err) { - console.error( - `Cursor error occurred for user: ${userKey} while attempting to get dmarcSummaryInfo while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - for (const ownership of dmarcSummaryCheckList) { - try { - await trx.step( - () => query` - WITH ownership, organizations, domains, dmarcSummaries, domainsToDmarcSummaries - LET dmarcSummaryEdges = ( - FOR v, e IN 1..1 OUTBOUND ${ownership._to} domainsToDmarcSummaries - RETURN { edgeKey: e._key, dmarcSummaryId: e._to } - ) - LET removeDmarcSummaryEdges = ( - FOR dmarcSummaryEdge IN dmarcSummaryEdges - REMOVE dmarcSummaryEdge.edgeKey IN domainsToDmarcSummaries - OPTIONS { waitForSync: true } - ) - LET removeDmarcSummary = ( - FOR dmarcSummaryEdge IN dmarcSummaryEdges - LET key = PARSE_IDENTIFIER(dmarcSummaryEdge.dmarcSummaryId).key - REMOVE key IN dmarcSummaries - OPTIONS { waitForSync: true } - ) - RETURN true - `, - ) - } catch (err) { - console.error( - `Trx step error occurred for user: ${userKey} while attempting to remove dmarc summaries while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - try { - await trx.step( - () => query` - WITH ownership, organizations, domains - REMOVE ${ownership._key} IN ownership - OPTIONS { waitForSync: true } - `, - ) - } catch (err) { - console.error( - `Trx step error occurred for user: ${userKey} while attempting to remove ownerships while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - } - - // check to see if any other orgs are using this domain - let countCursor - try { - countCursor = await query` - WITH claims, domains, organizations - LET domainIds = ( - FOR v, e IN 1..1 OUTBOUND ${organization._id} claims - RETURN e._to - ) - FOR domain IN domains - FILTER domain._id IN domainIds - LET count = LENGTH( - FOR v, e IN 1..1 INBOUND domain._id claims - RETURN 1 - ) - RETURN { - "_id": domain._id, - "_key": domain._key, - "domain": domain.domain, - "count": count - } - ` - } catch (err) { - console.error( - `Database error occurred for user: ${userKey} while attempting to gather domain count while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - let domainInfo - try { - domainInfo = await countCursor.all() - } catch (err) { - console.error( - `Cursor error occurred for user: ${userKey} while attempting to gather domain count while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - for (const domain of domainInfo) { - if (domain.count === 1) { - try { - // Remove web data - await trx.step(async () => { - await query` - WITH web, webScan - FOR webV, domainsWebEdge IN 1..1 OUTBOUND ${domain._id} domainsWeb - LET removeWebScansQuery = ( - FOR webScanV, webToWebScansV In 1..1 OUTBOUND webV._id webToWebScans - REMOVE webScanV IN webScan - REMOVE webToWebScansV IN webToWebScans - OPTIONS { waitForSync: true } - ) - REMOVE webV IN web - REMOVE domainsWebEdge IN domainsWeb - OPTIONS { waitForSync: true } - ` - }) - } catch (err) { - console.error( - `Trx step error occurred while user: ${userKey} attempted to remove web data for ${domain.domain} in org: ${organization.slug}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - try { - // Remove DNS data - await trx.step(async () => { - await query` - WITH dns - FOR dnsV, domainsDNSEdge IN 1..1 OUTBOUND ${domain._id} domainsDNS - REMOVE dnsV IN dns - REMOVE domainsDNSEdge IN domainsDNS - OPTIONS { waitForSync: true } - ` - }) - } catch (err) { - console.error( - `Trx step error occurred while user: ${userKey} attempted to remove DNS data for ${domain.domain} in org: ${organization.slug}, error: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - // remove favourites - try { - await trx.step(async () => { - await query` - WITH favourites, domains - FOR fav IN favourites - FILTER fav._to == ${domain._id} - REMOVE fav IN favourites - ` - }) - } catch (err) { - console.error( - `Trx step error occurred while user: ${userKey} attempted to remove favourites for ${domain.domain} in org: ${organization.slug}, error: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - // remove DKIM selectors - try { - await trx.step(async () => { - await query` - FOR e IN domainsToSelectors - FILTER e._from == ${domain._id} - REMOVE e IN domainsToSelectors - ` - }) - } catch (err) { - console.error( - `Trx step error occurred while user: ${userKey} attempted to remove DKIM selectors for ${domain.domain} in org: ${organization.slug}, error: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - try { - // Remove domain - await trx.step( - () => - query` - WITH claims, domains, organizations - LET domainEdges = ( - FOR v, e IN 1..1 OUTBOUND ${organization._id} claims - FILTER e._to == ${domain._id} - RETURN { edgeKey: e._key, domainId: e._to } - ) - LET removeDomainEdges = ( - FOR domainEdge in domainEdges - REMOVE domainEdge.edgeKey IN claims - OPTIONS { waitForSync: true } - ) - LET removeDomain = ( - FOR domainEdge in domainEdges - LET key = PARSE_IDENTIFIER(domainEdge.domainId).key - REMOVE key IN domains - OPTIONS { waitForSync: true } - ) - RETURN true - `, - ) - } catch (err) { - console.error( - `Trx step error occurred for user: ${userKey} while attempting to remove domains while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - } - } - - let orgCursor - let compareOrg - if (typeof organization !== 'undefined') { - // Get all org details for comparison - try { - orgCursor = await query` - WITH organizations - FOR org IN organizations - FILTER org._key == ${organization._key} - RETURN org - ` - } catch (err) {} - - try { - compareOrg = await orgCursor.next() - } catch (err) {} - } - - try { - await trx.step( - () => - query` - WITH affiliations, organizations, users - LET userEdges = ( - FOR v, e IN 1..1 OUTBOUND ${organization._id} affiliations - RETURN { edgeKey: e._key, userKey: e._to } - ) - LET removeUserEdges = ( - FOR userEdge IN userEdges - REMOVE userEdge.edgeKey IN affiliations - OPTIONS { waitForSync: true } - ) - RETURN true - `, - ) - - await trx.step( - () => - query` - WITH organizations, organizationSummaries - FOR summary in organizationSummaries - FILTER summary.organization == ${organization._id} - REMOVE summary._key IN organizationSummaries - OPTIONS { waitForSync: true } - `, - ) - - await trx.step( - () => - query` - WITH organizations - REMOVE ${organization._key} IN organizations - OPTIONS { waitForSync: true } - `, - ) - } catch (err) { - console.error( - `Trx step error occurred for user: ${userKey} while attempting to remove affiliations, and the org while removing org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error( - `Trx commit error occurred for user: ${userKey} while attempting remove of org: ${organization._key}, ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to remove organization. Please try again.`)) - } + const compareOrg = await organizationDS.getRawByKey({ orgKey: organization._key }) + await organizationDS.remove({ organization }) console.info(`User: ${userKey} successfully removed org: ${organization._key}.`) - await logActivity({ - transaction, - collections, - query, + await auditLogs.logActivity({ initiatedBy: { id: user._key, userName: user.userName, @@ -406,10 +95,10 @@ export const removeOrganization = new mutationWithClientMutationId({ action: 'delete', target: { resource: { - en: compareOrg.orgDetails.en.name || organization.name, - fr: compareOrg.orgDetails.fr.name || organization.name, - }, // name of resource being acted upon - resourceType: 'organization', // user, org, domain + en: compareOrg?.orgDetails.en.name || organization.name, + fr: compareOrg?.orgDetails.fr.name || organization.name, + }, + resourceType: 'organization', }, }) diff --git a/api/src/organization/mutations/update-organization.js b/api/src/organization/mutations/update-organization.js index 6221567bcd..8e6938a2e7 100644 --- a/api/src/organization/mutations/update-organization.js +++ b/api/src/organization/mutations/update-organization.js @@ -4,7 +4,7 @@ import { t } from '@lingui/macro' import { Acronym } from '../../scalars' import { updateOrganizationUnion } from '../unions' -import { logActivity } from '../../audit-logs/mutations/log-activity' +import ac from '../../access-control' export const updateOrganization = new mutationWithClientMutationId({ name: 'UpdateOrganization', @@ -90,13 +90,10 @@ export const updateOrganization = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, userKey, request: { ip }, auth: { checkPermission, userRequired, verifiedRequired }, - loaders: { loadOrgByKey }, + dataSources: { auditLogs, organization: organizationDS }, validators: { cleanseInput, slugify }, }, ) => { @@ -128,7 +125,7 @@ export const updateOrganization = new mutationWithClientMutationId({ const slugFR = slugify(nameFR) // Check to see if org exists - const currentOrg = await loadOrgByKey.load(orgKey) + const currentOrg = await organizationDS.byKey.load(orgKey) if (typeof currentOrg === 'undefined') { console.warn( @@ -144,7 +141,7 @@ export const updateOrganization = new mutationWithClientMutationId({ // Check to see if user has permission const permission = await checkPermission({ orgId: currentOrg._id }) - if (!['admin', 'owner', 'super_admin'].includes(permission)) { + if (!ac.can(permission).updateOwn('organization').granted) { console.error( `User: ${userKey} attempted to update organization ${orgKey}, however they do not have the correct permission level. Permission: ${permission}`, ) @@ -159,21 +156,7 @@ export const updateOrganization = new mutationWithClientMutationId({ // Check to see if any orgs already have the name in use if (nameEN !== '' || nameFR !== '') { - let orgNameCheckCursor - try { - orgNameCheckCursor = await query` - WITH organizations - FOR org IN organizations - FILTER (org.orgDetails.en.name == ${nameEN}) OR (org.orgDetails.fr.name == ${nameFR}) - RETURN org - ` - } catch (err) { - console.error( - `Database error occurred during name check when user: ${userKey} attempted to update org: ${currentOrg._key}, ${err}`, - ) - throw new Error(i18n._(t`Unable to update organization. Please try again.`)) - } - + const orgNameCheckCursor = await organizationDS.checkNameInUse({ nameEN, nameFR }) if (orgNameCheckCursor.count > 0) { console.error( `User: ${userKey} attempted to change the name of org: ${currentOrg._key} however it is already in use.`, @@ -186,27 +169,7 @@ export const updateOrganization = new mutationWithClientMutationId({ } } - // Get all org details for comparison - let orgCursor - try { - orgCursor = await query` - WITH organizations - FOR org IN organizations - FILTER org._key == ${orgKey} - RETURN org - ` - } catch (err) { - console.error(`Database error occurred while retrieving org: ${orgKey} for update, err: ${err}`) - throw new Error(i18n._(t`Unable to update organization. Please try again.`)) - } - - let compareOrg - try { - compareOrg = await orgCursor.next() - } catch (err) { - console.error(`Cursor error occurred while retrieving org: ${orgKey} for update, err: ${err}`) - throw new Error(i18n._(t`Unable to update organization. Please try again.`)) - } + const compareOrg = await organizationDS.getRawByKey({ orgKey }) const updatedOrgDetails = { orgDetails: { @@ -233,45 +196,18 @@ export const updateOrganization = new mutationWithClientMutationId({ }, } - if (permission === 'super_admin' && typeof args.externallyManaged !== 'undefined') { + if (ac.can(permission).updateAny('organization').granted && typeof args.externallyManaged !== 'undefined') { updatedOrgDetails.externallyManaged = args.externallyManaged } - if (permission === 'super_admin') { + if (ac.can(permission).updateAny('organization').granted) { updatedOrgDetails.externalId = externalId || compareOrg?.externalId } - // Setup Trans action - const trx = await transaction(collections) - - // Upsert new org details - try { - await trx.step( - async () => - await query` - WITH organizations - UPSERT { _key: ${orgKey} } - INSERT ${updatedOrgDetails} - UPDATE ${updatedOrgDetails} - IN organizations - `, - ) - } catch (err) { - console.error(`Transaction error occurred while upserting org: ${orgKey}, err: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to update organization. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Transaction error occurred while committing org: ${orgKey}, err: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to update organization. Please try again.`)) - } + await organizationDS.update({ orgKey, updatedOrgDetails }) - await loadOrgByKey.clear(orgKey) - const organization = await loadOrgByKey.load(orgKey) + await organizationDS.byKey.clear(orgKey) + const organization = await organizationDS.byKey.load(orgKey) console.info(`User: ${userKey}, successfully updated org ${orgKey}.`) @@ -305,10 +241,7 @@ export const updateOrganization = new mutationWithClientMutationId({ }) } if (updatedProperties.length > 0) { - await logActivity({ - transaction, - collections, - query, + await auditLogs.logActivity({ initiatedBy: { id: user._key, userName: user.userName, @@ -321,7 +254,7 @@ export const updateOrganization = new mutationWithClientMutationId({ en: compareOrg.orgDetails.en.name, fr: compareOrg.orgDetails.fr.name, }, - resourceType: 'organization', // user, org, domain + resourceType: 'organization', updatedProperties, }, }) diff --git a/api/src/organization/mutations/verify-organization.js b/api/src/organization/mutations/verify-organization.js index a09f64d886..dbb2bb2530 100644 --- a/api/src/organization/mutations/verify-organization.js +++ b/api/src/organization/mutations/verify-organization.js @@ -24,12 +24,9 @@ export const verifyOrganization = new mutationWithClientMutationId({ args, { i18n, - query, - collections, - transaction, userKey, auth: { checkPermission, userRequired, verifiedRequired }, - loaders: { loadOrgByKey }, + dataSources: { organization: organizationDS }, validators: { cleanseInput }, }, ) => { @@ -41,7 +38,7 @@ export const verifyOrganization = new mutationWithClientMutationId({ const { id: orgKey } = fromGlobalId(cleanseInput(args.orgId)) // Check to see if org exists - const currentOrg = await loadOrgByKey.load(orgKey) + const currentOrg = await organizationDS.byKey.load(orgKey) if (typeof currentOrg === 'undefined') { console.warn( @@ -82,54 +79,9 @@ export const verifyOrganization = new mutationWithClientMutationId({ } } - // Set org to verified currentOrg.verified = true - // Setup Trans action - const trx = await transaction(collections) - - // Upsert new org details - try { - await trx.step( - () => - query` - WITH organizations - UPSERT { _key: ${orgKey} } - INSERT ${currentOrg} - UPDATE ${currentOrg} - IN organizations - `, - ) - } catch (err) { - console.error(`Transaction error occurred while upserting verified org: ${orgKey}, err: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to verify organization. Please try again.`)) - } - - // unarchive all archived affiliated domains - try { - await trx.step( - () => - query` - WITH domains, claims - FOR v, e IN 1..1 OUTBOUND ${currentOrg._id} claims - FILTER v.archived == true - UPDATE v WITH { archived: false } IN domains - `, - ) - } catch (err) { - console.error(`Transaction error occurred while unarchiving affiliated domains for org: ${orgKey}, err: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to verify organization. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Transaction error occurred while committing newly verified org: ${orgKey}, err: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to verify organization. Please try again.`)) - } + await organizationDS.verify({ currentOrg }) console.info(`User: ${userKey}, successfully verified org: ${orgKey}.`) diff --git a/api/src/organization/objects/__tests__/organization.test.js b/api/src/organization/objects/__tests__/organization.test.js index 871611b23b..b88914a82f 100644 --- a/api/src/organization/objects/__tests__/organization.test.js +++ b/api/src/organization/objects/__tests__/organization.test.js @@ -213,7 +213,6 @@ describe('given the organization object', () => { describe('testing the domains resolver', () => { it('returns the resolved value', async () => { const demoType = organizationType.getFields() - const checkPermission = jest.fn().mockReturnValue('user') const expectedResult = { edges: [ @@ -243,7 +242,9 @@ describe('given the organization object', () => { { _id: 'organizations/1' }, { first: 1 }, { - auth: { checkPermission }, + dataSources: { + auth: { permissionByOrgId: { load: jest.fn().mockResolvedValue('user') } }, + }, loaders: { loadDomainConnectionsByOrgId: jest.fn().mockReturnValue(expectedResult), }, @@ -257,8 +258,6 @@ describe('given the organization object', () => { it('returns the resolved value', async () => { const demoType = organizationType.getFields() - const checkPermission = jest.fn().mockReturnValue('admin') - const expectedResults = { edges: [ { @@ -291,7 +290,11 @@ describe('given the organization object', () => { { _id: 'organizations/1' }, { first: 5 }, { - auth: { checkPermission }, + i18n, + auth: { loginRequiredBool: true }, + dataSources: { + auth: { permissionByOrgId: { load: jest.fn().mockResolvedValue('admin') } }, + }, loaders: { loadAffiliationConnectionsByOrgId: jest.fn().mockReturnValue(expectedResults), }, @@ -319,15 +322,16 @@ describe('given the organization object', () => { it('returns the resolved value', async () => { const demoType = organizationType.getFields() - const checkPermission = jest.fn().mockReturnValue('user') - try { await demoType.affiliations.resolve( { _id: '1' }, { first: 5 }, { i18n, - auth: { checkPermission }, + auth: { loginRequiredBool: true }, + dataSources: { + auth: { permissionByOrgId: { load: jest.fn().mockResolvedValue('user') } }, + }, loaders: { loadAffiliationConnectionsByOrgId: jest.fn() }, }, ) @@ -356,15 +360,16 @@ describe('given the organization object', () => { it('returns the resolved value', async () => { const demoType = organizationType.getFields() - const checkPermission = jest.fn().mockReturnValue('user') - try { await demoType.affiliations.resolve( { _id: '1' }, { first: 5 }, { i18n, - auth: { checkPermission }, + auth: { loginRequiredBool: true }, + dataSources: { + auth: { permissionByOrgId: { load: jest.fn().mockResolvedValue('user') } }, + }, loaders: { loadAffiliationConnectionsByOrgId: jest.fn() }, }, ) diff --git a/api/src/organization/objects/organization-summary.js b/api/src/organization/objects/organization-summary.js index 793acc5ea0..dbeaa82489 100644 --- a/api/src/organization/objects/organization-summary.js +++ b/api/src/organization/objects/organization-summary.js @@ -89,17 +89,17 @@ export const organizationSummaryType = new GraphQLObjectType({ dmarcPhase: { type: categorizedSummaryType, description: 'Summary based on DMARC phases for a given organization.', - resolve: ({ dmarc_phase }, _) => { + resolve: ({ dmarc_phase: dmarcPhase }, _) => { const categories = [ - createCategory('assess', dmarc_phase.assess, dmarc_phase.total), - createCategory('deploy', dmarc_phase.deploy, dmarc_phase.total), - createCategory('enforce', dmarc_phase.enforce, dmarc_phase.total), - createCategory('maintain', dmarc_phase.maintain, dmarc_phase.total), + createCategory('assess', dmarcPhase.assess, dmarcPhase.total), + createCategory('deploy', dmarcPhase.deploy, dmarcPhase.total), + createCategory('enforce', dmarcPhase.enforce, dmarcPhase.total), + createCategory('maintain', dmarcPhase.maintain, dmarcPhase.total), ] return { categories, - total: dmarc_phase.total, + total: dmarcPhase.total, } }, }, @@ -118,15 +118,15 @@ export const organizationSummaryType = new GraphQLObjectType({ webConnections: { type: categorizedSummaryType, description: 'Summary based on HTTPS and HSTS scan results for a given organization.', - resolve: ({ web_connections }, _) => { + resolve: ({ web_connections: webConnections }, _) => { const categories = [ - createCategory('pass', web_connections.pass, web_connections.total), - createCategory('fail', web_connections.fail, web_connections.total), + createCategory('pass', webConnections.pass, webConnections.total), + createCategory('fail', webConnections.fail, webConnections.total), ] return { categories, - total: web_connections.total, + total: webConnections.total, } }, }, @@ -167,20 +167,17 @@ export const organizationSummaryType = new GraphQLObjectType({ }, }, resolve: async ( - { negative_tags }, + { negative_tags: negativeTags }, args, - { - auth: { loginRequiredBool, userRequired, verifiedRequired }, - loaders: { loadGuidanceTagSummaryConnectionsByTagId }, - }, + { auth: { loginRequiredBool, userRequired, verifiedRequired }, dataSources: { guidanceTag } }, ) => { if (loginRequiredBool) { const user = await userRequired() verifiedRequired({ user }) } - const guidanceTags = await loadGuidanceTagSummaryConnectionsByTagId({ - guidanceTags: negative_tags, + const guidanceTags = await guidanceTag.summaryConnectionsByTagId({ + guidanceTags: negativeTags, ...args, }) return guidanceTags diff --git a/api/src/organization/objects/organization.js b/api/src/organization/objects/organization.js index b127dbc7ec..9dc814967b 100644 --- a/api/src/organization/objects/organization.js +++ b/api/src/organization/objects/organization.js @@ -9,9 +9,9 @@ import { affiliationUserOrder } from '../../affiliation/inputs' import { affiliationConnection } from '../../affiliation/objects' import { domainOrder, domainFilter } from '../../domain/inputs' import { domainConnection } from '../../domain/objects' -import { logActivity } from '../../audit-logs' import { OrderDirection } from '../../enums' import { tagType } from '../../tags/objects' +import ac from '../../access-control' export const organizationType = new GraphQLObjectType({ name: 'Organization', @@ -141,7 +141,7 @@ export const organizationType = new GraphQLObjectType({ { userKey, auth: { userRequired, loginRequiredBool, verifiedRequired }, - loaders: { loadOrganizationSummariesByPeriod }, + dataSources: { organization: organizationDS }, }, ) => { if (loginRequiredBool) { @@ -149,7 +149,7 @@ export const organizationType = new GraphQLObjectType({ verifiedRequired({ user }) } - const historicalSummaries = await loadOrganizationSummariesByPeriod({ + const historicalSummaries = await organizationDS.summariesByPeriod({ orgId: _id, ...args, }) @@ -179,26 +179,23 @@ export const organizationType = new GraphQLObjectType({ { i18n, userKey, - query, - transaction, - collections, request: { ip }, - auth: { checkPermission, userRequired, verifiedRequired }, - loaders: { loadOrganizationDomainStatuses }, + auth: { userRequired, verifiedRequired }, + dataSources: { auth: authDS, auditLogs, organization: organizationDS }, }, ) => { const user = await userRequired() verifiedRequired({ user }) - const permission = await checkPermission({ orgId: _id }) - if (!['user', 'admin', 'owner', 'super_admin'].includes(permission)) { + const permission = await authDS.permissionByOrgId.load(_id) + if (!ac.can(permission).createOwn('csv').granted) { console.error( `User "${userKey}" attempted to retrieve CSV output for organization "${_id}". Permission: ${permission}`, ) throw new Error(t`Permission Denied: Please contact organization user for help with retrieving this domain.`) } - const domains = await loadOrganizationDomainStatuses({ + const domains = await organizationDS.domainStatuses({ orgId: _id, ...args, }) @@ -223,6 +220,7 @@ export const organizationType = new GraphQLObjectType({ 'wildcardEntry', 'hasEntrustCertificate', 'top25Vulnerabilities', + 'cvdEnrollmentStatus', ] let csvOutput = headers.join(',') domains.forEach((domainDoc) => { @@ -230,15 +228,13 @@ export const organizationType = new GraphQLObjectType({ .map((header) => { if (['ipAddresses', 'tags', 'top25Vulnerabilities'].includes(header)) { return `"${domainDoc[header]?.join('|') || []}"` - } - if ( + } else if ( ['https', 'hsts', 'certificates', 'protocols', 'ciphers', 'curves', 'spf', 'dkim', 'dmarc'].includes( header, ) ) { return `"${domainDoc?.status[header]}"` - } - if (header === 'phase') { + } else if (header === 'phase') { switch (domainDoc[header]) { case 'assess': return i18n._(t`Assess`) @@ -259,36 +255,17 @@ export const organizationType = new GraphQLObjectType({ }) // Get org names to use in activity log - let orgNamesCursor - try { - orgNamesCursor = await query` - LET org = DOCUMENT(organizations, ${_id}) - RETURN { - "orgNameEN": org.orgDetails.en.name, - "orgNameFR": org.orgDetails.fr.name, - } - ` - } catch (err) { - console.error( - `Database error occurred when user: ${userKey} attempted to export org: ${_id}. Error while creating cursor for retrieving organization names. error: ${err}`, - ) - throw new Error(i18n._(t`Unable to export organization. Please try again.`)) - } - let orgNames try { - orgNames = await orgNamesCursor.next() + orgNames = await organizationDS.namesById.load(_id) } catch (err) { console.error( - `Cursor error occurred when user: ${userKey} attempted to export org: ${_id}. Error while retrieving organization names. error: ${err}`, + `Error occurred when user: ${userKey} attempted to export org: ${_id}. Error while retrieving organization names. error: ${err}`, ) throw new Error(i18n._(t`Unable to export organization. Please try again.`)) } - await logActivity({ - transaction, - collections, - query, + await auditLogs.logActivity({ initiatedBy: { id: user._key, userName: user.userName, @@ -304,7 +281,7 @@ export const organizationType = new GraphQLObjectType({ organization: { id: _id, name: orgNames.orgNameEN, - }, // name of resource being acted upon + }, resourceType: 'organization', }, }) @@ -338,10 +315,9 @@ export const organizationType = new GraphQLObjectType({ { _id }, args, - { auth: { checkPermission }, loaders: { loadDomainConnectionsByOrgId } }, + { dataSources: { auth: authDS }, loaders: { loadDomainConnectionsByOrgId } }, ) => { - // Check to see requesting users permission to the org is - const permission = await checkPermission({ orgId: _id }) + const permission = await authDS.permissionByOrgId.load(_id) const connections = await loadDomainConnectionsByOrgId({ orgId: _id, permission, @@ -371,10 +347,15 @@ export const organizationType = new GraphQLObjectType({ resolve: async ( { _id }, args, - { i18n, auth: { checkPermission, loginRequiredBool }, loaders: { loadAffiliationConnectionsByOrgId } }, + { + i18n, + auth: { loginRequiredBool }, + dataSources: { auth: authDS }, + loaders: { loadAffiliationConnectionsByOrgId }, + }, ) => { - const permission = await checkPermission({ orgId: _id }) - if (['user', 'admin', 'owner', 'super_admin'].includes(permission) === false && loginRequiredBool) { + const permission = await authDS.permissionByOrgId.load(_id) + if (!ac.can(permission).readOwn('affiliation').granted && loginRequiredBool) { throw new Error(i18n._(t`Cannot query affiliations on organization without admin permission or higher.`)) } @@ -389,8 +370,8 @@ export const organizationType = new GraphQLObjectType({ type: GraphQLBoolean, description: 'Value that determines if a user is affiliated with an organization, whether through organization affiliation, verified affiliation, or through super admin status.', - resolve: async ({ _id }, _args, { auth: { checkPermission } }) => { - const permission = await checkPermission({ orgId: _id }) + resolve: async ({ _id }, _args, { dataSources: { auth: authDS } }) => { + const permission = await authDS.permissionByOrgId.load(_id) return ['user', 'admin', 'super_admin', 'owner'].includes(permission) }, }, diff --git a/api/src/organization/queries/__tests__/find-my-organizations.test.js b/api/src/organization/queries/__tests__/find-my-organizations.test.js index 1440fb5e41..11ab3ea768 100644 --- a/api/src/organization/queries/__tests__/find-my-organizations.test.js +++ b/api/src/organization/queries/__tests__/find-my-organizations.test.js @@ -194,15 +194,13 @@ describe('given findMyOrganizationsQuery', () => { }), verifiedRequired: verifiedRequired({}), }, - loaders: { - loadOrgConnectionsByUserId: loadOrgConnectionsByUserId({ + dataSources: { organization: { connectionsByUserId: loadOrgConnectionsByUserId({ query, userKey: user._key, cleanseInput, auth: { loginRequired: true }, language: 'en', - }), - }, + }) } }, }, }) @@ -337,15 +335,13 @@ describe('given findMyOrganizationsQuery', () => { }), verifiedRequired: verifiedRequired({}), }, - loaders: { - loadOrgConnectionsByUserId: loadOrgConnectionsByUserId({ + dataSources: { organization: { connectionsByUserId: loadOrgConnectionsByUserId({ query, userKey: user._key, cleanseInput, auth: { loginRequired: true }, language: 'fr', - }), - }, + }) } }, }, }) @@ -457,16 +453,14 @@ describe('given findMyOrganizationsQuery', () => { userRequired: jest.fn().mockReturnValue({}), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgConnectionsByUserId: loadOrgConnectionsByUserId({ + dataSources: { organization: { connectionsByUserId: loadOrgConnectionsByUserId({ query: mockedQuery, userKey: user._key, cleanseInput, auth: { loginRequired: true }, language: 'en', i18n, - }), - }, + }) } }, }, }) @@ -535,16 +529,14 @@ describe('given findMyOrganizationsQuery', () => { userRequired: jest.fn().mockReturnValue({}), verifiedRequired: jest.fn(), }, - loaders: { - loadOrgConnectionsByUserId: loadOrgConnectionsByUserId({ + dataSources: { organization: { connectionsByUserId: loadOrgConnectionsByUserId({ query: mockedQuery, userKey: user._key, cleanseInput, auth: { loginRequired: true }, language: 'en', i18n, - }), - }, + }) } }, }, }) diff --git a/api/src/organization/queries/__tests__/find-organization-by-slug.test.js b/api/src/organization/queries/__tests__/find-organization-by-slug.test.js index 8a99ceb76c..cfb39fda7a 100644 --- a/api/src/organization/queries/__tests__/find-organization-by-slug.test.js +++ b/api/src/organization/queries/__tests__/find-organization-by-slug.test.js @@ -159,9 +159,13 @@ describe('given findOrganizationBySlugQuery', () => { cleanseInput, auth: { loginRequiredBool: true }, }, + dataSources: { + organization: { + byKey: loadOrgByKey(query, 'en'), + bySlug: loadOrgBySlug({ query, language: 'en' }), + }, + }, loaders: { - loadOrgByKey: loadOrgByKey(query, 'en'), - loadOrgBySlug: loadOrgBySlug({ query, language: 'en' }), loadUserByKey: loadUserByKey({ query }), loadDomainConnectionsByOrgId: loadDomainConnectionsByOrgId({ query, @@ -265,9 +269,13 @@ describe('given findOrganizationBySlugQuery', () => { cleanseInput, auth: { loginRequiredBool: true }, }, + dataSources: { + organization: { + byKey: loadOrgByKey(query, 'fr'), + bySlug: loadOrgBySlug({ query, language: 'fr' }), + }, + }, loaders: { - loadOrgByKey: loadOrgByKey(query, 'fr'), - loadOrgBySlug: loadOrgBySlug({ query, language: 'fr' }), loadUserByKey: loadUserByKey({ query }), loadDomainConnectionsByOrgId: loadDomainConnectionsByOrgId({ query, @@ -361,11 +369,9 @@ describe('given findOrganizationBySlugQuery', () => { cleanseInput, auth: { loginRequiredBool: true }, }, - loaders: { - loadOrgBySlug: { + dataSources: { organization: { bySlug: { load: jest.fn().mockReturnValue(), - }, - }, + } } }, }, }) @@ -410,11 +416,9 @@ describe('given findOrganizationBySlugQuery', () => { validators: { cleanseInput, }, - loaders: { - loadOrgBySlug: { + dataSources: { organization: { bySlug: { load: jest.fn().mockReturnValue({}), - }, - }, + } } }, }, }) @@ -477,11 +481,9 @@ describe('given findOrganizationBySlugQuery', () => { cleanseInput, auth: { loginRequiredBool: true }, }, - loaders: { - loadOrgBySlug: { + dataSources: { organization: { bySlug: { load: jest.fn().mockReturnValue(), - }, - }, + } } }, }, }) @@ -526,11 +528,9 @@ describe('given findOrganizationBySlugQuery', () => { validators: { cleanseInput, }, - loaders: { - loadOrgBySlug: { + dataSources: { organization: { bySlug: { load: jest.fn().mockReturnValue({}), - }, - }, + } } }, }, }) diff --git a/api/src/organization/queries/__tests__/get-all-organization-domain-statuses.test.js b/api/src/organization/queries/__tests__/get-all-organization-domain-statuses.test.js index 059e224b09..b8a25f8328 100644 --- a/api/src/organization/queries/__tests__/get-all-organization-domain-statuses.test.js +++ b/api/src/organization/queries/__tests__/get-all-organization-domain-statuses.test.js @@ -200,13 +200,11 @@ describe('given getAllOrganizationDomainStatuses', () => { superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadAllOrganizationDomainStatuses: loadAllOrganizationDomainStatuses({ + dataSources: { organization: { allDomainStatuses: loadAllOrganizationDomainStatuses({ query, userKey: user._key, i18n, - }), - }, + }) } }, }, }) const error = [ @@ -258,14 +256,12 @@ describe('given getAllOrganizationDomainStatuses', () => { superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadAllOrganizationDomainStatuses: loadAllOrganizationDomainStatuses({ + dataSources: { organization: { allDomainStatuses: loadAllOrganizationDomainStatuses({ query, userKey: user._key, i18n, language: 'en', - }), - }, + }) } }, }, }) @@ -318,13 +314,11 @@ describe('given getAllOrganizationDomainStatuses', () => { superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadAllOrganizationDomainStatuses: loadAllOrganizationDomainStatuses({ + dataSources: { organization: { allDomainStatuses: loadAllOrganizationDomainStatuses({ query, userKey: user._key, i18n, - }), - }, + }) } }, }, }) const error = [ @@ -377,14 +371,12 @@ describe('given getAllOrganizationDomainStatuses', () => { superAdminRequired: superAdminRequired({ i18n }), loginRequiredBool: loginRequiredBool, }, - loaders: { - loadAllOrganizationDomainStatuses: loadAllOrganizationDomainStatuses({ + dataSources: { organization: { allDomainStatuses: loadAllOrganizationDomainStatuses({ query, userKey: user._key, i18n, language: 'en', - }), - }, + }) } }, }, }) const expectedResponse = { diff --git a/api/src/organization/queries/find-my-organizations.js b/api/src/organization/queries/find-my-organizations.js index cc622c35ff..507de5032f 100644 --- a/api/src/organization/queries/find-my-organizations.js +++ b/api/src/organization/queries/find-my-organizations.js @@ -40,7 +40,7 @@ export const findMyOrganizations = { { userKey, auth: { checkSuperAdmin, userRequired, verifiedRequired, loginRequiredBool }, - loaders: { loadOrgConnectionsByUserId }, + dataSources: { organization: organizationDS }, }, ) => { if (loginRequiredBool) { @@ -50,7 +50,7 @@ export const findMyOrganizations = { const isSuperAdmin = await checkSuperAdmin() - const orgConnections = await loadOrgConnectionsByUserId({ + const orgConnections = await organizationDS.connectionsByUserId({ isSuperAdmin, ...args, }) diff --git a/api/src/organization/queries/find-organization-by-slug.js b/api/src/organization/queries/find-organization-by-slug.js index 9f7c4ed6d2..90919afe5a 100644 --- a/api/src/organization/queries/find-organization-by-slug.js +++ b/api/src/organization/queries/find-organization-by-slug.js @@ -1,6 +1,7 @@ import { GraphQLNonNull } from 'graphql' import { t } from '@lingui/macro' import { Slug } from '../../scalars' +import ac from '../../access-control' const { organizationType } = require('../objects') @@ -20,7 +21,7 @@ export const findOrganizationBySlug = { i18n, userKey, auth: { checkPermission, userRequired, verifiedRequired, loginRequiredBool }, - loaders: { loadOrgBySlug }, + dataSources: { organization: organizationDS }, validators: { cleanseInput }, }, ) => { @@ -34,7 +35,7 @@ export const findOrganizationBySlug = { const orgSlug = cleanseInput(args.orgSlug) // Retrieve organization by slug - const org = await loadOrgBySlug.load(orgSlug) + const org = await organizationDS.bySlug.load(orgSlug) if (typeof org === 'undefined') { console.warn(`User ${userKey} could not retrieve organization.`) @@ -44,16 +45,11 @@ export const findOrganizationBySlug = { // Check user permission for organization access const permission = await checkPermission({ orgId: org._id }) - if (loginRequiredBool) { - if (!['user', 'admin', 'owner', 'super_admin'].includes(permission)) { - console.warn(`User ${userKey} could not retrieve organization.`) - throw new Error(i18n._(t`Permission Denied: Could not retrieve specified organization.`)) - } - } else { - if (org.verified !== true && !['user', 'admin', 'owner', 'super_admin'].includes(permission)) { - console.warn(`User ${userKey} could not retrieve organization.`) - throw new Error(i18n._(t`Permission Denied: Could not retrieve specified organization.`)) - } + if (loginRequiredBool && !ac.can(permission).readOwn('organization').granted) { + console.warn(`User ${userKey} could not retrieve organization.`) + throw new Error(i18n._(t`Permission Denied: Could not retrieve specified organization.`)) + } else if (!loginRequiredBool && org.verified !== true && !ac.can(permission).readOwn('organization').granted) { + throw new Error(i18n._(t`Permission Denied: Could not retrieve specified organization.`)) } console.info(`User ${userKey} successfully retrieved organization ${org._key}.`) diff --git a/api/src/organization/queries/get-all-organization-domain-statuses.js b/api/src/organization/queries/get-all-organization-domain-statuses.js index faadfb512b..f982c98a2c 100644 --- a/api/src/organization/queries/get-all-organization-domain-statuses.js +++ b/api/src/organization/queries/get-all-organization-domain-statuses.js @@ -18,7 +18,7 @@ export const getAllOrganizationDomainStatuses = { { userKey, auth: { checkSuperAdmin, userRequired, verifiedRequired, superAdminRequired }, - loaders: { loadAllOrganizationDomainStatuses }, + dataSources: { organization: organizationDS }, }, ) => { const user = await userRequired() @@ -27,7 +27,7 @@ export const getAllOrganizationDomainStatuses = { const isSuperAdmin = await checkSuperAdmin() superAdminRequired({ user, isSuperAdmin }) - const domainStatuses = await loadAllOrganizationDomainStatuses({ ...args }) + const domainStatuses = await organizationDS.allDomainStatuses({ ...args }) console.info(`User ${userKey} successfully retrieved all domain statuses.`) diff --git a/api/src/scalars/__tests__/scalar-domain.test.js b/api/src/scalars/__tests__/scalar-domain.test.js index 5902145c1b..515a91114b 100644 --- a/api/src/scalars/__tests__/scalar-domain.test.js +++ b/api/src/scalars/__tests__/scalar-domain.test.js @@ -1,6 +1,6 @@ -import {Kind} from 'graphql' -import {stringify} from 'jest-matcher-utils' -import {Domain} from '../index' +import { GraphQLError, Kind } from 'graphql' +import { stringify } from 'jest-matcher-utils' +import { Domain } from '../index' describe('given a domain scalar', () => { describe('serializing inputs', () => { @@ -28,9 +28,7 @@ describe('given a domain scalar', () => { }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when serializing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when serializing ${stringify(invalidInput)}`, () => { expect(() => Domain.serialize(invalidInput)).toThrow( new TypeError(`Value is not a string: ${typeof invalidInput}`), ) @@ -52,16 +50,12 @@ describe('given a domain scalar', () => { }) describe('given an invalid domain', () => { const testDomain = 'not an domain' - expect(() => Domain.parseValue(testDomain)).toThrow( - new TypeError(`Value is not a valid domain: ${testDomain}`), - ) + expect(() => Domain.parseValue(testDomain)).toThrow(new TypeError(`Value is not a valid domain: ${testDomain}`)) }) }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when serializing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when serializing ${stringify(invalidInput)}`, () => { expect(() => Domain.parseValue(invalidInput)).toThrow( new TypeError(`Value is not a string: ${typeof invalidInput}`), ) @@ -110,13 +104,9 @@ describe('given a domain scalar', () => { kind: Kind.DOCUMENT, }, ].forEach((literal) => { - it(`throws an error when parsing invalid literal ${stringify( - literal, - )}`, () => { + it(`throws an error when parsing invalid literal ${stringify(literal)}`, () => { expect(() => Domain.parseLiteral(literal, {})).toThrow( - new TypeError( - `Can only validate strings as domains but got a: ${literal.kind}`, - ), + new GraphQLError(`Can only validate strings as domains but got a: ${literal.kind}`), ) }) }) diff --git a/api/src/scalars/__tests__/scalar-organization-acronym.test.js b/api/src/scalars/__tests__/scalar-organization-acronym.test.js index 0d2a0f2188..e9ff9c719e 100644 --- a/api/src/scalars/__tests__/scalar-organization-acronym.test.js +++ b/api/src/scalars/__tests__/scalar-organization-acronym.test.js @@ -1,6 +1,6 @@ -import {Kind} from 'graphql' -import {stringify} from 'jest-matcher-utils' -import {Acronym} from '../index' +import { GraphQLError, Kind } from 'graphql' +import { stringify } from 'jest-matcher-utils' +import { Acronym } from '../index' describe('given a acronym scalar', () => { describe('serializing inputs', () => { @@ -22,9 +22,7 @@ describe('given a acronym scalar', () => { }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when serializing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when serializing ${stringify(invalidInput)}`, () => { expect(() => Acronym.serialize(invalidInput)).toThrow( new TypeError(`Value is not string: ${typeof invalidInput}`), ) @@ -47,9 +45,7 @@ describe('given a acronym scalar', () => { }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when serializing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when serializing ${stringify(invalidInput)}`, () => { expect(() => Acronym.parseValue(invalidInput)).toThrow( new TypeError(`Value is not string: ${typeof invalidInput}`), ) @@ -88,13 +84,9 @@ describe('given a acronym scalar', () => { kind: Kind.DOCUMENT, }, ].forEach((literal) => { - it(`throws an error when parsing invalid literal ${stringify( - literal, - )}`, () => { + it(`throws an error when parsing invalid literal ${stringify(literal)}`, () => { expect(() => Acronym.parseLiteral(literal, {})).toThrow( - new TypeError( - `Can only validate strings as acronyms but got a: ${literal.kind}`, - ), + new GraphQLError(`Can only validate strings as acronyms but got a: ${literal.kind}`), ) }) }) diff --git a/api/src/scalars/__tests__/scalar-selector.test.js b/api/src/scalars/__tests__/scalar-selector.test.js index aaefa3c59d..d55c224733 100644 --- a/api/src/scalars/__tests__/scalar-selector.test.js +++ b/api/src/scalars/__tests__/scalar-selector.test.js @@ -1,4 +1,4 @@ -import { Kind } from 'graphql' +import { GraphQLError, Kind } from 'graphql' import { stringify } from 'jest-matcher-utils' import { Selectors, SelectorsInput } from '../index' @@ -48,7 +48,7 @@ describe("checking a 'selector' type", () => { ].forEach((literal) => { it(`throws an error when parsing invalid literal ${stringify(literal)}`, () => { expect(() => Selectors.parseLiteral(literal, {})).toThrow( - new TypeError(`Can only validate strings as selectors but got a: ${literal.kind}`), + new GraphQLError(`Can only validate strings as selectors but got a: ${literal.kind}`), ) }) }) diff --git a/api/src/scalars/__tests__/scalar-slug.test.js b/api/src/scalars/__tests__/scalar-slug.test.js index 361ef066a8..5a024d33a4 100644 --- a/api/src/scalars/__tests__/scalar-slug.test.js +++ b/api/src/scalars/__tests__/scalar-slug.test.js @@ -1,6 +1,6 @@ -import {Kind} from 'graphql' -import {stringify} from 'jest-matcher-utils' -import {Slug} from '../index' +import { GraphQLError, Kind } from 'graphql' +import { stringify } from 'jest-matcher-utils' +import { Slug } from '../index' describe('given a slug scalar', () => { describe('serializing inputs', () => { @@ -15,18 +15,14 @@ describe('given a slug scalar', () => { describe('given an invalid slug', () => { it('throws an error', () => { const testSlug = 'This is an invalid slug' - expect(() => Slug.serialize(testSlug)).toThrow( - new TypeError(`Value is not a valid slug: ${testSlug}`), - ) + expect(() => Slug.serialize(testSlug)).toThrow(new TypeError(`Value is not a valid slug: ${testSlug}`)) }) }) }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when serializing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when serializing ${stringify(invalidInput)}`, () => { expect(() => Slug.serialize(invalidInput)).toThrow( new TypeError(`Value is not string: ${typeof invalidInput}`), ) @@ -46,17 +42,13 @@ describe('given a slug scalar', () => { describe('given an invalid slug', () => { it('throws a type error', () => { const testSlug = 'invalid slug' - expect(() => Slug.parseValue(testSlug)).toThrow( - new TypeError(`Value is not a valid slug: ${testSlug}`), - ) + expect(() => Slug.parseValue(testSlug)).toThrow(new TypeError(`Value is not a valid slug: ${testSlug}`)) }) }) }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when value parsing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when value parsing ${stringify(invalidInput)}`, () => { expect(() => Slug.parseValue(invalidInput)).toThrow( new TypeError(`Value is not string: ${typeof invalidInput}`), ) @@ -96,13 +88,9 @@ describe('given a slug scalar', () => { kind: Kind.DOCUMENT, }, ].forEach((literal) => { - it(`throws an error when parsing invalid literal ${stringify( - literal, - )}`, () => { + it(`throws an error when parsing invalid literal ${stringify(literal)}`, () => { expect(() => Slug.parseLiteral(literal, {})).toThrow( - new TypeError( - `Can only validate strings as slug but got a: ${literal.kind}`, - ), + new GraphQLError(`Can only validate strings as slug but got a: ${literal.kind}`), ) }) }) diff --git a/api/src/scalars/__tests__/scalar-year.test.js b/api/src/scalars/__tests__/scalar-year.test.js index 76437352ee..7ac751ed3a 100644 --- a/api/src/scalars/__tests__/scalar-year.test.js +++ b/api/src/scalars/__tests__/scalar-year.test.js @@ -1,6 +1,6 @@ -import {Kind} from 'graphql' -import {stringify} from 'jest-matcher-utils' -import {Year} from '../index' +import { GraphQLError, Kind } from 'graphql' +import { stringify } from 'jest-matcher-utils' +import { Year } from '../index' describe('given a year scalar', () => { describe('serializing inputs', () => { @@ -14,17 +14,13 @@ describe('given a year scalar', () => { describe('given an invalid year', () => { it('throws a typeError', () => { const testYear = 'Text' - expect(() => Year.serialize(testYear)).toThrow( - new TypeError(`Value is not a valid year: ${testYear}`), - ) + expect(() => Year.serialize(testYear)).toThrow(new TypeError(`Value is not a valid year: ${testYear}`)) }) }) }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when serializing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when serializing ${stringify(invalidInput)}`, () => { expect(() => Year.serialize(invalidInput)).toThrow( new TypeError(`Value is not string: ${typeof invalidInput}`), ) @@ -43,16 +39,12 @@ describe('given a year scalar', () => { }) describe('given an invalid year', () => { const testYear = 'Text' - expect(() => Year.parseValue(testYear)).toThrow( - new TypeError(`Value is not a valid year: ${testYear}`), - ) + expect(() => Year.parseValue(testYear)).toThrow(new TypeError(`Value is not a valid year: ${testYear}`)) }) }) describe('given invalid inputs', () => { ;[123, {}, [], null, undefined, true].forEach((invalidInput) => { - it(`throws an error when serializing ${stringify( - invalidInput, - )}`, () => { + it(`throws an error when serializing ${stringify(invalidInput)}`, () => { expect(() => Year.parseValue(invalidInput)).toThrow( new TypeError(`Value is not string: ${typeof invalidInput}`), ) @@ -92,13 +84,9 @@ describe('given a year scalar', () => { kind: Kind.DOCUMENT, }, ].forEach((literal) => { - it(`throws an error when parsing invalid literal ${stringify( - literal, - )}`, () => { + it(`throws an error when parsing invalid literal ${stringify(literal)}`, () => { expect(() => Year.parseLiteral(literal, {})).toThrow( - new TypeError( - `Can only validate strings as year but got a: ${literal.kind}`, - ), + new GraphQLError(`Can only validate strings as year but got a: ${literal.kind}`), ) }) }) diff --git a/api/src/summaries/data-source.js b/api/src/summaries/data-source.js new file mode 100644 index 0000000000..4b534206b5 --- /dev/null +++ b/api/src/summaries/data-source.js @@ -0,0 +1,7 @@ +import { loadChartSummariesByPeriod } from './loaders' + +export class SummariesDataSource { + constructor({ query, userKey, cleanseInput, i18n }) { + this.getConnectionsByPeriod = loadChartSummariesByPeriod({ query, userKey, cleanseInput, i18n }) + } +} diff --git a/api/src/summaries/index.js b/api/src/summaries/index.js index 7dab4e57a0..fd864e4e36 100644 --- a/api/src/summaries/index.js +++ b/api/src/summaries/index.js @@ -1,3 +1,4 @@ export * from './loaders' export * from './objects' export * from './queries' +export * from './data-source' diff --git a/api/src/summaries/loaders/__tests__/load-chart-summary-by-key.test.js b/api/src/summaries/loaders/__tests__/load-chart-summary-by-key.test.js deleted file mode 100644 index ac697bd07b..0000000000 --- a/api/src/summaries/loaders/__tests__/load-chart-summary-by-key.test.js +++ /dev/null @@ -1,217 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { loadChartSummaryByKey } from '../../index' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given the loadChartSummaryByKey function', () => { - let query, drop, truncate, collections, i18n - - const consoleErrorOutput = [] - const mockedError = (output) => consoleErrorOutput.push(output) - - beforeAll(() => { - console.error = mockedError - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleErrorOutput.length = 0 - }) - - describe('given a successful load', () => { - beforeAll(async () => { - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - web: { - total: 1000, - fail: 500, - pass: 500, - }, - mail: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - describe('given a single id', () => { - it('returns a single summary', async () => { - const expectedCursor = await query` - FOR summary IN chartSummaries - SORT summary.date DESC LIMIT 1 - RETURN summary.web - ` - const expectedSummary = await expectedCursor.next() - - const loader = loadChartSummaryByKey({ query, i18n }) - const webSummary = await loader.load('web') - - expect(webSummary).toEqual(expectedSummary) - }) - }) - describe('given multiple ids', () => { - it('returns multiple dkim scans', async () => { - const summaryKeys = [] - const expectedSummaries = [] - const expectedCursor = await query` - FOR summary IN chartSummaries - SORT summary.date DESC LIMIT 1 - RETURN summary - ` - - while (expectedCursor.hasMore) { - const tempSummary = await expectedCursor.next() - summaryKeys.push(tempSummary._key) - expectedSummaries.push(tempSummary) - } - - const loader = loadChartSummaryByKey({ query, i18n }) - const chartSummaries = await loader.loadMany(summaryKeys) - expect(chartSummaries).toEqual(expectedSummaries) - }) - }) - }) - describe('given an unsuccessful load', () => { - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given a database error', () => { - it('raises an error', async () => { - query = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadChartSummaryByKey({ query, userKey: '1234', i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Unable to load summary. Please try again.')) - } - - expect(consoleErrorOutput).toEqual([ - `Database error occurred when user: 1234 running loadChartSummaryByKey: Error: Database error occurred.`, - ]) - }) - }) - describe('given a cursor error', () => { - it('raises an error', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - query = jest.fn().mockReturnValue(cursor) - const loader = loadChartSummaryByKey({ query, userKey: '1234', i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Unable to load summary. Please try again.')) - } - - expect(consoleErrorOutput).toEqual([ - `Cursor error occurred when user: 1234 running loadChartSummaryByKey: Error: Cursor error occurred.`, - ]) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given a database error', () => { - it('raises an error', async () => { - query = jest.fn().mockRejectedValue(new Error('Database error occurred.')) - const loader = loadChartSummaryByKey({ query, userKey: '1234', i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le résumé. Veuillez réessayer.')) - } - - expect(consoleErrorOutput).toEqual([ - `Database error occurred when user: 1234 running loadChartSummaryByKey: Error: Database error occurred.`, - ]) - }) - }) - describe('given a cursor error', () => { - it('raises an error', async () => { - const cursor = { - next() { - throw new Error('Cursor error occurred.') - }, - } - query = jest.fn().mockReturnValue(cursor) - const loader = loadChartSummaryByKey({ query, userKey: '1234', i18n }) - - try { - await loader.load('1') - } catch (err) { - expect(err).toEqual(new Error('Impossible de charger le résumé. Veuillez réessayer.')) - } - - expect(consoleErrorOutput).toEqual([ - `Cursor error occurred when user: 1234 running loadChartSummaryByKey: Error: Cursor error occurred.`, - ]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/loaders/index.js b/api/src/summaries/loaders/index.js index 69e452cece..427499a436 100644 --- a/api/src/summaries/loaders/index.js +++ b/api/src/summaries/loaders/index.js @@ -1,2 +1 @@ -export * from './load-chart-summary-by-key' export * from './load-chart-summaries-by-period' diff --git a/api/src/summaries/loaders/load-chart-summary-by-key.js b/api/src/summaries/loaders/load-chart-summary-by-key.js deleted file mode 100644 index 719c0162f6..0000000000 --- a/api/src/summaries/loaders/load-chart-summary-by-key.js +++ /dev/null @@ -1,29 +0,0 @@ -import DataLoader from 'dataloader' -import { t } from '@lingui/macro' - -export const loadChartSummaryByKey = ({ query, userKey, i18n }) => - new DataLoader(async (keys) => { - let cursor - - try { - cursor = await query` - WITH chartSummaries - FOR summary IN chartSummaries - SORT summary.date DESC LIMIT 1 - RETURN summary - ` - } catch (err) { - console.error(`Database error occurred when user: ${userKey} running loadChartSummaryByKey: ${err}`) - throw new Error(i18n._(t`Unable to load summary. Please try again.`)) - } - - let summariesMap - try { - summariesMap = await cursor.next() - } catch (err) { - console.error(`Cursor error occurred when user: ${userKey} running loadChartSummaryByKey: ${err}`) - throw new Error(i18n._(t`Unable to load summary. Please try again.`)) - } - - return keys.map((key) => summariesMap[key]) - }) diff --git a/api/src/summaries/objects/chart-summary.js b/api/src/summaries/objects/chart-summary.js index bc4c3a4ebb..9dda9c6004 100644 --- a/api/src/summaries/objects/chart-summary.js +++ b/api/src/summaries/objects/chart-summary.js @@ -3,8 +3,25 @@ import { categorizedSummaryType } from './categorized-summary' import { globalIdField } from 'graphql-relay' import { GraphQLDate } from 'graphql-scalars' +const makeCategory = (key) => ({ + type: categorizedSummaryType, + resolve: (parent) => { + const data = parent[key] + const total = data.total + const safe = total > 0 + return { + total, + categories: [ + { name: 'pass', count: data.pass, percentage: safe ? Number(((data.pass / total) * 100).toFixed(1)) : 0 }, + { name: 'fail', count: data.fail, percentage: safe ? Number(((data.fail / total) * 100).toFixed(1)) : 0 }, + ], + } + }, +}) + export const chartSummaryType = new GraphQLObjectType({ name: 'ChartSummary', + description: `This object contains the information for each type of summary that has been pre-computed`, fields: () => ({ id: globalIdField('chartSummary'), date: { @@ -12,308 +29,33 @@ export const chartSummaryType = new GraphQLObjectType({ description: 'Date that the summary was computed.', resolve: ({ date }) => date, }, - https: { - type: categorizedSummaryType, - description: 'https summary data', - resolve: ({ https }) => { - let percentPass, percentageFail - if (https.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((https.pass / https.total) * 100).toFixed(1)) - percentageFail = Number(((https.fail / https.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: https.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: https.fail, - percentage: percentageFail, - }, - ] - - return { - categories, - total: https.total, - } - }, - }, - dmarc: { - type: categorizedSummaryType, - description: 'dmarc summary data', - resolve: ({ dmarc }) => { - let percentPass, percentageFail - if (dmarc.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((dmarc.pass / dmarc.total) * 100).toFixed(1)) - percentageFail = Number(((dmarc.fail / dmarc.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: dmarc.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: dmarc.fail, - percentage: percentageFail, - }, - ] - - return { - categories, - total: dmarc.total, - } - }, - }, - mail: { - type: categorizedSummaryType, - description: 'Summary based on mail scan results for all domains.', - resolve: ({ mail }, _) => { - let percentPass, percentageFail - if (mail.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((mail.pass / mail.total) * 100).toFixed(1)) - percentageFail = Number(((mail.fail / mail.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: mail.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: mail.fail, - percentage: percentageFail, - }, - ] - - return { - categories, - total: mail.total, - } - }, - }, - web: { - type: categorizedSummaryType, - description: 'Summary based on web scan results for all domains.', - resolve: ({ web }, _) => { - let percentPass, percentageFail - if (web.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((web.pass / web.total) * 100).toFixed(1)) - percentageFail = Number(((web.fail / web.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: web.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: web.fail, - percentage: percentageFail, - }, - ] - - return { - categories, - total: web.total, - } - }, - }, - dmarcPhase: { - type: categorizedSummaryType, - description: 'Summary based on DMARC phases for all domains.', - resolve: ({ dmarc_phase }, _) => { - let percentAssess, percentDeploy, percentEnforce, percentMaintain - if (dmarc_phase.total <= 0) { - percentAssess = 0 - percentDeploy = 0 - percentEnforce = 0 - percentMaintain = 0 - } else { - percentAssess = Number(((dmarc_phase.assess / dmarc_phase.total) * 100).toFixed(1)) - percentDeploy = Number(((dmarc_phase.deploy / dmarc_phase.total) * 100).toFixed(1)) - percentEnforce = Number(((dmarc_phase.enforce / dmarc_phase.total) * 100).toFixed(1)) - percentMaintain = Number(((dmarc_phase.maintain / dmarc_phase.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'assess', - count: dmarc_phase.assess, - percentage: percentAssess, - }, - { - name: 'deploy', - count: dmarc_phase.deploy, - percentage: percentDeploy, - }, - { - name: 'enforce', - count: dmarc_phase.enforce, - percentage: percentEnforce, - }, - { - name: 'maintain', - count: dmarc_phase.maintain, - percentage: percentMaintain, - }, - ] - - return { - categories, - total: dmarc_phase.total, - } - }, - }, - ssl: { - type: categorizedSummaryType, - description: 'Summary based on SSL scan results for all domains.', - resolve: ({ ssl }, _) => { - let percentPass, percentageFail - if (ssl.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((ssl.pass / ssl.total) * 100).toFixed(1)) - percentageFail = Number(((ssl.fail / ssl.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: ssl.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: ssl.fail, - percentage: percentageFail, - }, - ] - - return { - categories, - total: ssl.total, - } - }, - }, + https: { ...makeCategory('https'), description: 'https summary data' }, + dmarc: { ...makeCategory('dmarc'), description: 'dmarc summary data' }, + mail: { ...makeCategory('mail'), description: 'Summary based on mail scan results for all domains.' }, + web: { ...makeCategory('web'), description: 'Summary based on web scan results for all domains.' }, + ssl: { ...makeCategory('ssl'), description: 'Summary based on SSL scan results for all domains.' }, webConnections: { - type: categorizedSummaryType, + ...makeCategory('web_connections'), description: 'Summary based on HTTPS and HSTS scan results for all domains.', - resolve: ({ web_connections }, _) => { - let percentPass, percentageFail - if (web_connections.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((web_connections.pass / web_connections.total) * 100).toFixed(1)) - percentageFail = Number(((web_connections.fail / web_connections.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: web_connections.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: web_connections.fail, - percentage: percentageFail, - }, - ] - - return { - categories, - total: web_connections.total, - } - }, - }, - spf: { - type: categorizedSummaryType, - description: 'Summary based on SPF scan results for all domains.', - resolve: ({ spf }, _) => { - let percentPass, percentageFail - if (spf.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((spf.pass / spf.total) * 100).toFixed(1)) - percentageFail = Number(((spf.fail / spf.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: spf.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: spf.fail, - percentage: percentageFail, - }, - ] - - return { - categories, - total: spf.total, - } - }, }, - dkim: { + spf: { ...makeCategory('spf'), description: 'Summary based on SPF scan results for all domains.' }, + dkim: { ...makeCategory('dkim'), description: 'Summary based on DKIM scan results for all domains.' }, + dmarcPhase: { type: categorizedSummaryType, - description: 'Summary based on DKIM scan results for all domains.', - resolve: ({ dkim }, _) => { - let percentPass, percentageFail - if (dkim.total <= 0) { - percentPass = 0 - percentageFail = 0 - } else { - percentPass = Number(((dkim.pass / dkim.total) * 100).toFixed(1)) - percentageFail = Number(((dkim.fail / dkim.total) * 100).toFixed(1)) - } - - const categories = [ - { - name: 'pass', - count: dkim.pass, - percentage: percentPass, - }, - { - name: 'fail', - count: dkim.fail, - percentage: percentageFail, - }, - ] - + description: 'Summary based on DMARC phases for all domains.', + resolve: ({ dmarc_phase: dmarcPhase }) => { + const total = dmarcPhase.total + const safe = total > 0 + const phaseNames = ['assess', 'deploy', 'enforce', 'maintain'] return { - categories, - total: dkim.total, + total, + categories: phaseNames.map((name) => ({ + name, + count: dmarcPhase[name], + percentage: safe ? Number(((dmarcPhase[name] / total) * 100).toFixed(1)) : 0, + })), } }, }, }), - description: `This object contains the information for each type of summary that has been pre-computed`, }) diff --git a/api/src/summaries/queries/__tests__/dkim-summary.test.js b/api/src/summaries/queries/__tests__/dkim-summary.test.js deleted file mode 100644 index 75481e8f91..0000000000 --- a/api/src/summaries/queries/__tests__/dkim-summary.test.js +++ /dev/null @@ -1,173 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given dkimSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful dkim summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - dkim: { total: 1000, fail: 500, pass: 500 }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns dkim summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - dkimSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - dkimSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful dkim summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - dkimSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load DKIM summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve DKIM summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/dmarc-phase-summary.test.js b/api/src/summaries/queries/__tests__/dmarc-phase-summary.test.js deleted file mode 100644 index 2545791525..0000000000 --- a/api/src/summaries/queries/__tests__/dmarc-phase-summary.test.js +++ /dev/null @@ -1,241 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given dmarcPhaseSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(async () => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - - beforeEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful dmarc phase summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - dmarc_phase: { - assess: 200, - deploy: 200, - enforce: 200, - maintain: 200, - total: 800, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns dmarc phase summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - dmarcPhaseSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - dmarcPhaseSummary: { - total: 800, - categories: [ - { - name: 'assess', - count: 200, - percentage: 25, - }, - { - name: 'deploy', - count: 200, - percentage: 25, - }, - { - name: 'enforce', - count: 200, - percentage: 25, - }, - { - name: 'maintain', - count: 200, - percentage: 25, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful dmarc phase summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - dmarcPhaseSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load DMARC phase summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve DMARC phase summary.`]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful dmarc phase summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - dmarcPhaseSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de charger le résumé DMARC. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve DMARC phase summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/dmarc-summary.test.js b/api/src/summaries/queries/__tests__/dmarc-summary.test.js deleted file mode 100644 index 1a100dad14..0000000000 --- a/api/src/summaries/queries/__tests__/dmarc-summary.test.js +++ /dev/null @@ -1,177 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given dmarcSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful dmarc summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - dmarc: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns dmarc summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - dmarcSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - dmarcSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful dmarc summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - dmarcSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load DMARC summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve DMARC summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/find-chart-summaries.test.js b/api/src/summaries/queries/__tests__/find-chart-summaries.test.js index d137c2a2c7..81455dd068 100644 --- a/api/src/summaries/queries/__tests__/find-chart-summaries.test.js +++ b/api/src/summaries/queries/__tests__/find-chart-summaries.test.js @@ -155,14 +155,14 @@ describe('given findMyOrganizationsQuery', () => { }), verifiedRequired: verifiedRequired({}), }, - loaders: { - loadChartSummariesByPeriod: loadChartSummariesByPeriod({ + dataSources: { + summaries: { getConnectionsByPeriod: loadChartSummariesByPeriod({ query, userKey: user._key, cleanseInput, auth: { loginRequired: true }, language: 'en', - }), + }) }, }, }, }) @@ -305,15 +305,15 @@ describe('given findMyOrganizationsQuery', () => { userRequired: jest.fn().mockReturnValue({}), verifiedRequired: jest.fn(), }, - loaders: { - loadChartSummariesByPeriod: loadChartSummariesByPeriod({ + dataSources: { + summaries: { getConnectionsByPeriod: loadChartSummariesByPeriod({ query: mockedQuery, userKey: user._key, cleanseInput, auth: { loginRequired: true }, language: 'en', i18n, - }), + }) }, }, }, }) diff --git a/api/src/summaries/queries/__tests__/https-summary.test.js b/api/src/summaries/queries/__tests__/https-summary.test.js deleted file mode 100644 index 47d3d3919d..0000000000 --- a/api/src/summaries/queries/__tests__/https-summary.test.js +++ /dev/null @@ -1,229 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given httpsSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(async () => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - - beforeEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful https summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - https: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns https summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - httpsSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - httpsSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful https summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - httpsSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load HTTPS summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve HTTPS summary.`]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful https summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - httpsSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de charger le résumé HTTPS. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve HTTPS summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/mail-summary.test.js b/api/src/summaries/queries/__tests__/mail-summary.test.js deleted file mode 100644 index 1711ca2de5..0000000000 --- a/api/src/summaries/queries/__tests__/mail-summary.test.js +++ /dev/null @@ -1,229 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given mailSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(async () => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - - beforeEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful mail summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - mail: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns mail summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - mailSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - mailSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful mail summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - mailSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load mail summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve mail summary.`]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful mail summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - mailSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de charger le résumé du courrier. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve mail summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/spf-summary.test.js b/api/src/summaries/queries/__tests__/spf-summary.test.js deleted file mode 100644 index 095b282fb8..0000000000 --- a/api/src/summaries/queries/__tests__/spf-summary.test.js +++ /dev/null @@ -1,177 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given spfSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful spf summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - spf: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns spf summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - spfSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - spfSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful spf summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - spfSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load SPF summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve SPF summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/ssl-summary.test.js b/api/src/summaries/queries/__tests__/ssl-summary.test.js deleted file mode 100644 index c3a813a039..0000000000 --- a/api/src/summaries/queries/__tests__/ssl-summary.test.js +++ /dev/null @@ -1,177 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given sslSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful ssl summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - ssl: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns ssl summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - sslSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - sslSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful ssl summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - sslSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load SSL summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve SSL summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/web-connections-summary.test.js b/api/src/summaries/queries/__tests__/web-connections-summary.test.js deleted file mode 100644 index afd2dd17c7..0000000000 --- a/api/src/summaries/queries/__tests__/web-connections-summary.test.js +++ /dev/null @@ -1,177 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given webConnectionsSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful webConnections summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2021-01-01', - web_connections: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns webConnections summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - webConnectionsSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - webConnectionsSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful webConnections summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - webConnectionsSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load web connections summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve web connections summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/__tests__/web-summary.test.js b/api/src/summaries/queries/__tests__/web-summary.test.js deleted file mode 100644 index 4b1a8dc3bb..0000000000 --- a/api/src/summaries/queries/__tests__/web-summary.test.js +++ /dev/null @@ -1,228 +0,0 @@ -import { dbNameFromFile } from 'arango-tools' -import { ensureDatabase as ensure } from '../../../testUtilities' -import { graphql, GraphQLSchema, GraphQLError } from 'graphql' -import { setupI18n } from '@lingui/core' - -import englishMessages from '../../../locale/en/messages' -import frenchMessages from '../../../locale/fr/messages' -import { createQuerySchema } from '../../../query' -import { createMutationSchema } from '../../../mutation' -import { loadChartSummaryByKey } from '../../loaders' -import dbschema from '../../../../database.json' - -const { DB_PASS: rootPass, DB_URL: url } = process.env - -describe('given webSummary query', () => { - let query, drop, truncate, schema, collections, i18n - - const consoleOutput = [] - const mockedInfo = (output) => consoleOutput.push(output) - const mockedWarn = (output) => consoleOutput.push(output) - const mockedError = (output) => consoleOutput.push(output) - beforeAll(() => { - console.info = mockedInfo - console.warn = mockedWarn - console.error = mockedError - // Create GQL Schema - schema = new GraphQLSchema({ - query: createQuerySchema(), - mutation: createMutationSchema(), - }) - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - afterEach(() => { - consoleOutput.length = 0 - }) - - describe('given successful web summary retrieval', () => { - beforeAll(async () => { - // Generate DB Items - ;({ query, drop, truncate, collections } = await ensure({ - variables: { - dbname: dbNameFromFile(__filename), - username: 'root', - rootPassword: rootPass, - password: rootPass, - url, - }, - - schema: dbschema, - })) - }) - beforeEach(async () => { - await collections.chartSummaries.save({ - date: '2020-10-02', - web: { - total: 1000, - fail: 500, - pass: 500, - }, - }) - }) - afterEach(async () => { - await truncate() - }) - afterAll(async () => { - await drop() - }) - it('returns web summary', async () => { - const response = await graphql({ - schema, - source: ` - query { - webSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: loadChartSummaryByKey({ query }), - }, - }, - }) - - const expectedResponse = { - data: { - webSummary: { - total: 1000, - categories: [ - { - name: 'pass', - count: 500, - percentage: 50, - }, - { - name: 'fail', - count: 500, - percentage: 50, - }, - ], - }, - }, - } - expect(response).toEqual(expectedResponse) - }) - }) - - describe('users language is set to english', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'en', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful web summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - webSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError(`Unable to load web summary. Please try again.`)] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve web summary.`]) - }) - }) - }) - }) - describe('users language is set to french', () => { - beforeAll(() => { - i18n = setupI18n({ - locale: 'fr', - localeData: { - en: { plurals: {} }, - fr: { plurals: {} }, - }, - locales: ['en', 'fr'], - messages: { - en: englishMessages.messages, - fr: frenchMessages.messages, - }, - }) - }) - describe('given unsuccessful web summary retrieval', () => { - describe('summary cannot be found', () => { - it('returns an appropriate error message', async () => { - const response = await graphql({ - schema, - source: ` - query { - webSummary { - total - categories { - name - count - percentage - } - } - } - `, - rootValue: null, - contextValue: { - i18n, - loaders: { - loadChartSummaryByKey: { - load: jest.fn().mockReturnValue(undefined), - }, - }, - }, - }) - - const error = [new GraphQLError('Impossible de charger le résumé web. Veuillez réessayer.')] - - expect(response.errors).toEqual(error) - expect(consoleOutput).toEqual([`User could not retrieve web summary.`]) - }) - }) - }) - }) -}) diff --git a/api/src/summaries/queries/dkim-summary.js b/api/src/summaries/queries/dkim-summary.js deleted file mode 100644 index 9a91978ce4..0000000000 --- a/api/src/summaries/queries/dkim-summary.js +++ /dev/null @@ -1,33 +0,0 @@ -import { categorizedSummaryType } from '../objects' -import { t } from '@lingui/macro' - -export const dkimSummary = { - type: categorizedSummaryType, - description: 'DKIM summary computed values, used to build summary cards.', - resolve: async (_, __, { i18n, loaders: { loadChartSummaryByKey } }) => { - const summary = await loadChartSummaryByKey.load('dkim') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve DKIM summary.`) - throw new Error(i18n._(t`Unable to load DKIM summary. Please try again.`)) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/summaries/queries/dmarc-phase-summary.js b/api/src/summaries/queries/dmarc-phase-summary.js deleted file mode 100644 index a48bcd1787..0000000000 --- a/api/src/summaries/queries/dmarc-phase-summary.js +++ /dev/null @@ -1,27 +0,0 @@ -import { categorizedSummaryType } from '../objects' -import { t } from '@lingui/macro' - -export const dmarcPhaseSummary = { - type: categorizedSummaryType, - description: 'DMARC phase summary computed values, used to build summary cards.', - resolve: async (_, __, { i18n, loaders: { loadChartSummaryByKey } }) => { - const summary = await loadChartSummaryByKey.load('dmarc_phase') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve DMARC phase summary.`) - throw new Error(i18n._(t`Unable to load DMARC phase summary. Please try again.`)) - } - const phaseNames = ['assess', 'deploy', 'enforce', 'maintain'] - const { total } = summary - const categories = phaseNames.map((name) => ({ - name, - count: summary[name], - percentage: Number(((summary[name] / total) * 100).toFixed(1)), - })) - - return { - categories, - total, - } - }, -} diff --git a/api/src/summaries/queries/dmarc-summary.js b/api/src/summaries/queries/dmarc-summary.js deleted file mode 100644 index e7ca64b3c8..0000000000 --- a/api/src/summaries/queries/dmarc-summary.js +++ /dev/null @@ -1,33 +0,0 @@ -import { categorizedSummaryType } from '../objects' -import { t } from '@lingui/macro' - -export const dmarcSummary = { - type: categorizedSummaryType, - description: 'DMARC summary computed values, used to build summary cards.', - resolve: async (_, __, { i18n, loaders: { loadChartSummaryByKey } }) => { - const summary = await loadChartSummaryByKey.load('dmarc') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve DMARC summary.`) - throw new Error(i18n._(t`Unable to load DMARC summary. Please try again.`)) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/summaries/queries/find-chart-summaries.js b/api/src/summaries/queries/find-chart-summaries.js index 73c7957e70..0da7b349fa 100644 --- a/api/src/summaries/queries/find-chart-summaries.js +++ b/api/src/summaries/queries/find-chart-summaries.js @@ -27,14 +27,14 @@ export const findChartSummaries = { resolve: async ( _, args, - { userKey, auth: { userRequired, loginRequiredBool, verifiedRequired }, loaders: { loadChartSummariesByPeriod } }, + { userKey, auth: { userRequired, loginRequiredBool, verifiedRequired }, dataSources: { summaries } }, ) => { if (loginRequiredBool) { const user = await userRequired() verifiedRequired({ user }) } - const summaryConnections = await loadChartSummariesByPeriod({ ...args }) + const summaryConnections = await summaries.getConnectionsByPeriod({ ...args }) console.info(`User: ${userKey} successfully retrieved their chart summaries.`) return summaryConnections diff --git a/api/src/summaries/queries/https-summary.js b/api/src/summaries/queries/https-summary.js deleted file mode 100644 index 781a23ab83..0000000000 --- a/api/src/summaries/queries/https-summary.js +++ /dev/null @@ -1,35 +0,0 @@ -import {categorizedSummaryType} from '../objects' -import {t} from '@lingui/macro' - -export const httpsSummary = { - type: categorizedSummaryType, - description: 'HTTPS summary computed values, used to build summary cards.', - resolve: async (_, __, {i18n, loaders: {loadChartSummaryByKey}}) => { - const summary = await loadChartSummaryByKey.load('https') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve HTTPS summary.`) - throw new Error( - i18n._(t`Unable to load HTTPS summary. Please try again.`), - ) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/summaries/queries/index.js b/api/src/summaries/queries/index.js index 50087ebeed..8002030019 100644 --- a/api/src/summaries/queries/index.js +++ b/api/src/summaries/queries/index.js @@ -1,10 +1 @@ -export * from './dkim-summary' -export * from './dmarc-phase-summary' -export * from './dmarc-summary' -export * from './https-summary' -export * from './mail-summary' -export * from './spf-summary' -export * from './ssl-summary' -export * from './web-connections-summary' -export * from './web-summary' export * from './find-chart-summaries' diff --git a/api/src/summaries/queries/mail-summary.js b/api/src/summaries/queries/mail-summary.js deleted file mode 100644 index 71f46a8bff..0000000000 --- a/api/src/summaries/queries/mail-summary.js +++ /dev/null @@ -1,33 +0,0 @@ -import {categorizedSummaryType} from '../objects' -import {t} from '@lingui/macro' - -export const mailSummary = { - type: categorizedSummaryType, - description: 'Email summary computed values, used to build summary cards.', - resolve: async (_, __, {i18n, loaders: {loadChartSummaryByKey}}) => { - const summary = await loadChartSummaryByKey.load('mail') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve mail summary.`) - throw new Error(i18n._(t`Unable to load mail summary. Please try again.`)) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/summaries/queries/spf-summary.js b/api/src/summaries/queries/spf-summary.js deleted file mode 100644 index c320ff40ff..0000000000 --- a/api/src/summaries/queries/spf-summary.js +++ /dev/null @@ -1,33 +0,0 @@ -import { categorizedSummaryType } from '../objects' -import { t } from '@lingui/macro' - -export const spfSummary = { - type: categorizedSummaryType, - description: 'SPF summary computed values, used to build summary cards.', - resolve: async (_, __, { i18n, loaders: { loadChartSummaryByKey } }) => { - const summary = await loadChartSummaryByKey.load('spf') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve SPF summary.`) - throw new Error(i18n._(t`Unable to load SPF summary. Please try again.`)) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/summaries/queries/ssl-summary.js b/api/src/summaries/queries/ssl-summary.js deleted file mode 100644 index ceafecefde..0000000000 --- a/api/src/summaries/queries/ssl-summary.js +++ /dev/null @@ -1,33 +0,0 @@ -import { categorizedSummaryType } from '../objects' -import { t } from '@lingui/macro' - -export const sslSummary = { - type: categorizedSummaryType, - description: 'SSL summary computed values, used to build summary cards.', - resolve: async (_, __, { i18n, loaders: { loadChartSummaryByKey } }) => { - const summary = await loadChartSummaryByKey.load('ssl') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve SSL summary.`) - throw new Error(i18n._(t`Unable to load SSL summary. Please try again.`)) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/summaries/queries/web-connections-summary.js b/api/src/summaries/queries/web-connections-summary.js deleted file mode 100644 index a25acc7d38..0000000000 --- a/api/src/summaries/queries/web-connections-summary.js +++ /dev/null @@ -1,33 +0,0 @@ -import { categorizedSummaryType } from '../objects' -import { t } from '@lingui/macro' - -export const webConnectionsSummary = { - type: categorizedSummaryType, - description: 'Web connections (HTTPS + HSTS) summary computed values, used to build summary cards.', - resolve: async (_, __, { i18n, loaders: { loadChartSummaryByKey } }) => { - const summary = await loadChartSummaryByKey.load('web_connections') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve web connections summary.`) - throw new Error(i18n._(t`Unable to load web connections summary. Please try again.`)) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/summaries/queries/web-summary.js b/api/src/summaries/queries/web-summary.js deleted file mode 100644 index 63347617b4..0000000000 --- a/api/src/summaries/queries/web-summary.js +++ /dev/null @@ -1,34 +0,0 @@ -import {t} from '@lingui/macro' - -import {categorizedSummaryType} from '../objects' - -export const webSummary = { - type: categorizedSummaryType, - description: 'Web summary computed values, used to build summary cards.', - resolve: async (_, __, {i18n, loaders: {loadChartSummaryByKey}}) => { - const summary = await loadChartSummaryByKey.load('web') - - if (typeof summary === 'undefined') { - console.warn(`User could not retrieve web summary.`) - throw new Error(i18n._(t`Unable to load web summary. Please try again.`)) - } - - const categories = [ - { - name: 'pass', - count: summary.pass, - percentage: Number(((summary.pass / summary.total) * 100).toFixed(1)), - }, - { - name: 'fail', - count: summary.fail, - percentage: Number(((summary.fail / summary.total) * 100).toFixed(1)), - }, - ] - - return { - categories, - total: summary.total, - } - }, -} diff --git a/api/src/tags/data-source.js b/api/src/tags/data-source.js new file mode 100644 index 0000000000..5199e29c96 --- /dev/null +++ b/api/src/tags/data-source.js @@ -0,0 +1,106 @@ +import { t } from '@lingui/macro' +import { loadAllTags, loadTagByTagId, loadTagsByOrg } from './loaders' + +export class TagsDataSource { + constructor({ query, userKey, i18n, language, transaction, collections }) { + this._query = query + this._userKey = userKey + this._i18n = i18n + this._transaction = transaction + this._collections = collections + this.all = loadAllTags({ query, userKey, i18n, language }) + this.byTagId = loadTagByTagId({ query, userKey, i18n, language }) + this.byOrg = loadTagsByOrg({ query, userKey, i18n, language }) + } + + // Fetch the raw DB document (label/description as {en, fr} objects, not translated strings). + // Used by mutations that need to read current field values before updating. + async getRaw(tagId) { + const { _query, _userKey, _i18n } = this + let cursor + try { + cursor = await _query` + WITH tags + FOR tag IN tags + FILTER tag.tagId == ${tagId} + RETURN tag + ` + } catch (err) { + console.error(`Database error occurred while retrieving tag: ${tagId} for user: ${_userKey}, err: ${err}`) + throw new Error(_i18n._(t`Unable to update tag. Please try again.`)) + } + try { + return await cursor.next() + } catch (err) { + console.error(`Cursor error occurred while retrieving tag: ${tagId} for user: ${_userKey}, err: ${err}`) + throw new Error(_i18n._(t`Unable to update tag. Please try again.`)) + } + } + + // Insert or update a tag, then return the freshly loaded record. + async create(tag) { + const { _query, _userKey, _i18n, _transaction, _collections } = this + const trx = await _transaction(_collections) + try { + await trx.step( + () => + _query` + UPSERT { tagId: ${tag.tagId} } + INSERT ${tag} + UPDATE ${tag} + IN tags + RETURN NEW + `, + ) + } catch (err) { + console.error(`Transaction step error occurred for user: ${_userKey} when inserting new tag: ${err}`) + await trx.abort() + throw new Error(_i18n._(t`Unable to create tag. Please try again.`)) + } + try { + await trx.commit() + } catch (err) { + console.error(`Transaction commit error occurred while user: ${_userKey} was creating tag: ${err}`) + await trx.abort() + throw new Error(_i18n._(t`Unable to create tag. Please try again.`)) + } + this.byTagId.clear(tag.tagId) + return this.byTagId.load(tag.tagId) + } + + // Update an existing tag matched by matchTagId (which may differ from tag.tagId after a label rename), + // then return the freshly loaded record. + async save(matchTagId, tag) { + const { _query, _userKey, _i18n, _transaction, _collections } = this + const trx = await _transaction(_collections) + try { + await trx.step( + async () => + await _query` + WITH tags + UPSERT { tagId: ${matchTagId} } + INSERT ${tag} + UPDATE ${tag} + IN tags + `, + ) + } catch (err) { + console.error( + `Transaction step error occurred when user: ${_userKey} attempted to update tag: ${matchTagId}, error: ${err}`, + ) + await trx.abort() + throw new Error(_i18n._(t`Unable to update tag. Please try again.`)) + } + try { + await trx.commit() + } catch (err) { + console.error( + `Transaction commit error occurred when user: ${_userKey} attempted to update tag: ${matchTagId}, error: ${err}`, + ) + await trx.abort() + throw new Error(_i18n._(t`Unable to update tag. Please try again.`)) + } + this.byTagId.clear(tag.tagId) + return this.byTagId.load(tag.tagId) + } +} diff --git a/api/src/tags/index.js b/api/src/tags/index.js index 1b5bd9dcd0..64ebb55b97 100644 --- a/api/src/tags/index.js +++ b/api/src/tags/index.js @@ -1,3 +1,4 @@ +export * from './data-source' export * from './loaders' export * from './mutations' export * from './objects' diff --git a/api/src/tags/mutations/create-tag.js b/api/src/tags/mutations/create-tag.js index 603af4b8af..293dbc2165 100644 --- a/api/src/tags/mutations/create-tag.js +++ b/api/src/tags/mutations/create-tag.js @@ -3,7 +3,7 @@ import { fromGlobalId, mutationWithClientMutationId } from 'graphql-relay' import { t } from '@lingui/macro' import { createTagUnion } from '../unions' import { TagOwnershipEnums } from '../../enums' -import { logActivity } from '../../audit-logs' +import ac from '../../access-control' export const createTag = new mutationWithClientMutationId({ name: 'CreateTag', @@ -50,12 +50,10 @@ export const createTag = new mutationWithClientMutationId({ { i18n, request, - query, - collections, - transaction, userKey, auth: { userRequired, verifiedRequired, checkPermission, checkSuperAdmin, superAdminRequired }, - loaders: { loadTagByTagId, loadOrgByKey }, + loaders: { loadOrgByKey }, + dataSources: { tags, auditLogs }, validators: { cleanseInput, slugify }, }, ) => { @@ -83,7 +81,7 @@ export const createTag = new mutationWithClientMutationId({ organizations: [], } - const tag = await loadTagByTagId.load(insertTag.tagId) + const tag = await tags.byTagId.load(insertTag.tagId) const isSuperAdmin = await checkSuperAdmin() if (ownership === 'global') { @@ -98,9 +96,6 @@ export const createTag = new mutationWithClientMutationId({ } } - // Setup Transaction - const trx = await transaction(collections) - let permission, org if (ownership === 'org') { if (typeof orgId === 'undefined') { @@ -126,7 +121,7 @@ export const createTag = new mutationWithClientMutationId({ } permission = await checkPermission({ orgId: org._id }) - if (!['super_admin', 'admin', 'owner'].includes(permission)) { + if (!ac.can(permission).createOwn('tag').granted) { console.warn( `User: ${userKey} attempted to create a tag in: ${org.slug}, however they do not have permission to do so.`, ) @@ -155,41 +150,11 @@ export const createTag = new mutationWithClientMutationId({ } } - try { - await trx.step( - () => - query` - UPSERT { tagId: ${insertTag.tagId} } - INSERT ${insertTag} - UPDATE ${insertTag} - IN tags - RETURN NEW - `, - ) - } catch (err) { - console.error(`Transaction step error occurred for user: ${userKey} when inserting new tag: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to create tag. Please try again.`)) - } - - try { - await trx.commit() - } catch (err) { - console.error(`Transaction commit error occurred while user: ${userKey} was creating tag: ${err}`) - await trx.abort() - throw new Error(i18n._(t`Unable to create tag. Please try again.`)) - } - - // Clear dataloader incase anything was updated or inserted into tag - await loadTagByTagId.clear(insertTag.tagId) - const returnTag = await loadTagByTagId.load(insertTag.tagId) + const returnTag = await tags.create(insertTag) console.info(`User: ${userKey} successfully created tag ${returnTag.tagId}`) - await logActivity({ - transaction, - collections, - query, + await auditLogs.logActivity({ initiatedBy: { id: user._key, userName: user.userName, diff --git a/api/src/tags/mutations/update-tag.js b/api/src/tags/mutations/update-tag.js index 5e7630c68f..bf50c1b3bb 100644 --- a/api/src/tags/mutations/update-tag.js +++ b/api/src/tags/mutations/update-tag.js @@ -3,7 +3,7 @@ import { fromGlobalId, mutationWithClientMutationId } from 'graphql-relay' import { t } from '@lingui/macro' import { updateTagUnion } from '../unions' import { TagOwnershipEnums } from '../../enums' -import { logActivity } from '../../audit-logs' +import ac from '../../access-control' export const updateTag = new mutationWithClientMutationId({ name: 'UpdateTag', @@ -54,13 +54,11 @@ export const updateTag = new mutationWithClientMutationId({ { i18n, request, - query, - collections, - transaction, userKey, auth: { userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired, checkPermission }, validators: { cleanseInput, slugify }, - loaders: { loadTagByTagId, loadOrgByKey }, + loaders: { loadOrgByKey }, + dataSources: { tags, auditLogs }, }, ) => { // Get User @@ -77,26 +75,7 @@ export const updateTag = new mutationWithClientMutationId({ const isVisible = args.isVisible const { type: _orgType, id: orgId } = fromGlobalId(cleanseInput(args.orgId)) - let tagCursor - try { - tagCursor = await query` - WITH tags - FOR tag IN tags - FILTER tag.tagId == ${tagId} - RETURN tag - ` - } catch (err) { - console.error(`Database error occurred while retrieving tag: ${tagId} for update, err: ${err}`) - throw new Error(i18n._(t`Unable to update tag. Please try again.`)) - } - - let compareTag - try { - compareTag = await tagCursor.next() - } catch (err) { - console.error(`Cursor error occurred while retrieving tag: ${tagId} for update, err: ${err}`) - throw new Error(i18n._(t`Unable to update tag. Please try again.`)) - } + const compareTag = await tags.getRaw(tagId) if (typeof compareTag === 'undefined') { console.warn( @@ -136,7 +115,7 @@ export const updateTag = new mutationWithClientMutationId({ } permission = await checkPermission({ orgId: org._id }) - if (!['super_admin', 'admin', 'owner'].includes(permission)) { + if (!ac.can(permission).updateOwn('tag').granted) { console.warn( `User: ${userKey} attempted to update a tag in: ${org.slug}, however they do not have permission to do so.`, ) @@ -173,7 +152,7 @@ export const updateTag = new mutationWithClientMutationId({ const updatedTagId = slugify(`${labelEn || compareTag.label.en}-${labelFr || compareTag.label.fr}`) if (tagId !== updatedTagId) { - const existingTag = await loadTagByTagId.load(updatedTagId) + const existingTag = await tags.byTagId.load(updatedTagId) if (typeof existingTag !== 'undefined' && !['org', 'pending'].includes(compareTag.ownership)) { console.warn(`User: ${userKey} attempted to update a tag that already exists: ${updatedTagId}`) return { @@ -199,42 +178,7 @@ export const updateTag = new mutationWithClientMutationId({ ownership: ownership || compareTag.ownership, } - // Setup Transaction - const trx = await transaction(collections) - - try { - await trx.step( - async () => - await query` - WITH tags - UPSERT { tagId: ${tagId} } - INSERT ${updatedTag} - UPDATE ${updatedTag} - IN tags - `, - ) - } catch (err) { - console.error( - `Transaction step error occurred when user: ${userKey} attempted to update tag: ${tagId}, error: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to update tag. Please try again.`)) - } - - // Commit transaction - try { - await trx.commit() - } catch (err) { - console.error( - `Transaction commit error occurred when user: ${userKey} attempted to update tag: ${tagId}, error: ${err}`, - ) - await trx.abort() - throw new Error(i18n._(t`Unable to update tag. Please try again.`)) - } - - // Clear dataloader and load updated tag - await loadTagByTagId.clear(updatedTag.tagId) - const returnTag = await loadTagByTagId.load(updatedTag.tagId) + const returnTag = await tags.save(tagId, updatedTag) console.info(`User: ${userKey} successfully updated tag: ${tagId}.`) @@ -282,10 +226,7 @@ export const updateTag = new mutationWithClientMutationId({ }) } - await logActivity({ - transaction, - collections, - query, + await auditLogs.logActivity({ initiatedBy: { id: user._key, userName: user.userName, diff --git a/api/src/tags/queries/__tests__/find-all-tags.test.js b/api/src/tags/queries/__tests__/find-all-tags.test.js index 5165a7dfab..1673b6cbad 100644 --- a/api/src/tags/queries/__tests__/find-all-tags.test.js +++ b/api/src/tags/queries/__tests__/find-all-tags.test.js @@ -1,10 +1,10 @@ import { findAllTags } from '../find-all-tags' describe('findAllTags', () => { - let loadAllTags, userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired, userKey, context, cleanseInput + let tagsAll, userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired, userKey, context, cleanseInput beforeEach(() => { - loadAllTags = jest.fn() + tagsAll = jest.fn() userRequired = jest.fn() verifiedRequired = jest.fn() checkSuperAdmin = jest.fn() @@ -14,7 +14,8 @@ describe('findAllTags', () => { userKey = 'test-user' context = { userKey, - loaders: { loadAllTags }, + dataSources: { tags: { all: tagsAll } }, + loaders: { loadOrgByKey: jest.fn() }, auth: { userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired }, validators: { cleanseInput }, } @@ -32,27 +33,27 @@ describe('findAllTags', () => { organizations: [], }, ] - loadAllTags.mockResolvedValue(tags) + tagsAll.mockResolvedValue(tags) const result = await findAllTags.resolve(null, { isVisible: false }, context) - expect(loadAllTags).toHaveBeenCalledWith({ isVisible: false, orgId: null }) + expect(tagsAll).toHaveBeenCalledWith({ isVisible: false, orgId: null }) expect(result).toEqual(tags) }) it('should apply visible filter when isVisible is true', async () => { const tags = [{ tagId: '1', label: 'Tag1', description: 'Description1', visible: true, ownership: 'global' }] - loadAllTags.mockResolvedValue(tags) + tagsAll.mockResolvedValue(tags) const result = await findAllTags.resolve(null, { isVisible: true }, context) - expect(loadAllTags).toHaveBeenCalledWith({ isVisible: true, orgId: null }) + expect(tagsAll).toHaveBeenCalledWith({ isVisible: true, orgId: null }) expect(result).toEqual(tags) }) it('should log a message when tags are successfully retrieved', async () => { const tags = [{ tagId: '1', label: 'Tag1', description: 'Description1', visible: true, ownership: 'global' }] - loadAllTags.mockResolvedValue(tags) + tagsAll.mockResolvedValue(tags) console.info = jest.fn() await findAllTags.resolve(null, { isVisible: false }, context) @@ -61,7 +62,7 @@ describe('findAllTags', () => { }) it('should throw an error when loadAllTags fails', async () => { - loadAllTags.mockRejectedValue(new Error('Load error')) + tagsAll.mockRejectedValue(new Error('Load error')) await expect(findAllTags.resolve(null, { isVisible: false }, context)).rejects.toThrow('Load error') }) diff --git a/api/src/tags/queries/find-all-tags.js b/api/src/tags/queries/find-all-tags.js index e7a5bdb2bb..31b58c411f 100644 --- a/api/src/tags/queries/find-all-tags.js +++ b/api/src/tags/queries/find-all-tags.js @@ -21,7 +21,8 @@ export const findAllTags = { { userKey, auth: { userRequired, verifiedRequired, checkSuperAdmin, superAdminRequired }, - loaders: { loadAllTags, loadOrgByKey }, + loaders: { loadOrgByKey }, + dataSources: { tags: tagsSource }, validators: { cleanseInput }, }, ) => { @@ -39,7 +40,7 @@ export const findAllTags = { superAdminRequired({ user, isSuperAdmin }) } - const tags = await loadAllTags({ ...args, orgId: orgKey }) + const tags = await tagsSource.all({ ...args, orgId: orgKey }) console.info(`User: ${userKey} successfully retrieved tags.`) return tags }, diff --git a/api/src/user/mutations/__tests__/sign-in.test.js b/api/src/user/mutations/__tests__/sign-in.test.js index 57dd730dc2..933c264e7c 100644 --- a/api/src/user/mutations/__tests__/sign-in.test.js +++ b/api/src/user/mutations/__tests__/sign-in.test.js @@ -146,7 +146,7 @@ describe('authenticate user account', () => { await query` FOR user IN users UPDATE ${user._key} WITH { tfaSendMethod: 'not_none', lastLogin: ${new Date( - new Date().setDate(new Date().getDate() - 30), + new Date().setDate(new Date().getDate() - 31), ).toISOString()} } IN users ` diff --git a/api/src/user/mutations/__tests__/update-user-profile.test.js b/api/src/user/mutations/__tests__/update-user-profile.test.js index cb36221f39..ad8bfb23bf 100644 --- a/api/src/user/mutations/__tests__/update-user-profile.test.js +++ b/api/src/user/mutations/__tests__/update-user-profile.test.js @@ -239,7 +239,7 @@ describe('authenticate user account', () => { } expect(response).toEqual(expectedResponse) - expect(sendVerificationEmail).toBeCalledWith({ + expect(sendVerificationEmail).toHaveBeenCalledWith({ verifyUrl: verifyUrl, userKey: user._key, displayName: user.displayName, @@ -939,7 +939,7 @@ describe('authenticate user account', () => { } expect(response).toEqual(expectedResponse) - expect(sendVerificationEmail).toBeCalledWith({ + expect(sendVerificationEmail).toHaveBeenCalledWith({ verifyUrl: verifyUrl, userKey: user._key, displayName: user.displayName, diff --git a/api/src/user/queries/is-user-admin.js b/api/src/user/queries/is-user-admin.js index 2f454bce5f..108947b7a2 100644 --- a/api/src/user/queries/is-user-admin.js +++ b/api/src/user/queries/is-user-admin.js @@ -24,20 +24,14 @@ export const isUserAdmin = { }, ) => { const { id: orgKey } = fromGlobalId(cleanseInput(args.orgId)) - const user = await userRequired() // check if for a specific org - if (orgKey !== '') { + if (orgKey) { const org = await loadOrgByKey.load(orgKey) - const permission = await checkPermission({ orgId: org._id }) - if (permission === 'admin' || permission === 'super_admin') { - return true - } - - return false + return ['admin', 'owner', 'super_admin'].includes(permission) } // check to see if user is an admin or higher for at least one org @@ -55,10 +49,6 @@ export const isUserAdmin = { throw new Error(i18n._(t`Unable to verify if user is an admin, please try again.`)) } - if (userAdmin.count > 0) { - return true - } - - return false + return userAdmin.count > 0 }, } diff --git a/api/src/web-scan/data-source.js b/api/src/web-scan/data-source.js new file mode 100644 index 0000000000..a7abd16a94 --- /dev/null +++ b/api/src/web-scan/data-source.js @@ -0,0 +1,8 @@ +import { loadWebConnectionsByDomainId, loadWebScansByWebId } from './loaders' + +export class WebScanDataSource { + constructor({ query, userKey, cleanseInput, i18n }) { + this.getConnectionsByDomainId = loadWebConnectionsByDomainId({ query, userKey, cleanseInput, i18n }) + this.getScansByWebId = loadWebScansByWebId({ query, userKey, cleanseInput, i18n }) + } +} diff --git a/api/src/web-scan/index.js b/api/src/web-scan/index.js index 84c283025a..d1175cffd4 100644 --- a/api/src/web-scan/index.js +++ b/api/src/web-scan/index.js @@ -1,2 +1,3 @@ export * from './loaders' export * from './objects' +export * from './data-source' diff --git a/api/src/web-scan/objects/tls-result.js b/api/src/web-scan/objects/tls-result.js index 3ae6e5b1e0..78e1d541bc 100644 --- a/api/src/web-scan/objects/tls-result.js +++ b/api/src/web-scan/objects/tls-result.js @@ -53,22 +53,22 @@ export const tlsResultType = new GraphQLObjectType({ positiveTags: { type: new GraphQLList(guidanceTagType), description: `List of positive tags for the scanned server from this scan.`, - resolve: async ({ positiveTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: positiveTags }) + resolve: async ({ positiveTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: positiveTags }) }, }, neutralTags: { type: new GraphQLList(guidanceTagType), description: `List of neutral tags for the scanned server from this scan.`, - resolve: async ({ neutralTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: neutralTags }) + resolve: async ({ neutralTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: neutralTags }) }, }, negativeTags: { type: new GraphQLList(guidanceTagType), description: `List of negative tags for the scanned server from this scan.`, - resolve: async ({ negativeTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: negativeTags }) + resolve: async ({ negativeTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: negativeTags }) }, }, certificateStatus: { diff --git a/api/src/web-scan/objects/web-connection-result.js b/api/src/web-scan/objects/web-connection-result.js index 926e1452df..d043e081dd 100644 --- a/api/src/web-scan/objects/web-connection-result.js +++ b/api/src/web-scan/objects/web-connection-result.js @@ -68,22 +68,22 @@ export const webConnectionResultType = new GraphQLObjectType({ positiveTags: { type: new GraphQLList(guidanceTagType), description: `List of positive tags for the scanned server from this scan.`, - resolve: async ({ positiveTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: positiveTags }) + resolve: async ({ positiveTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: positiveTags }) }, }, neutralTags: { type: new GraphQLList(guidanceTagType), description: `List of neutral tags for the scanned server from this scan.`, - resolve: async ({ neutralTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: neutralTags }) + resolve: async ({ neutralTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: neutralTags }) }, }, negativeTags: { type: new GraphQLList(guidanceTagType), description: `List of negative tags for the scanned server from this scan.`, - resolve: async ({ negativeTags }, _, { loaders: { loadGuidanceTagByTagId } }) => { - return await loadGuidanceTagByTagId({ tags: negativeTags }) + resolve: async ({ negativeTags }, _, { dataSources: { guidanceTag } }) => { + return await guidanceTag.byTagId({ tags: negativeTags }) }, }, }), @@ -183,5 +183,57 @@ export const connectionChainResultType = new GraphQLObjectType({ type: new GraphQLList(connectionType), description: `The connection chain created when following redirects.`, }, + securityTxt: { + type: new GraphQLList(securityTxtResultType), + description: 'Result of fetching and parsing the security.txt file for this domain.', + }, + }), +}) + +export const securityTxtResultType = new GraphQLObjectType({ + name: 'SecurityTxtResult', + description: 'Represents the result of a security.txt file fetch and parse operation.', + fields: () => ({ + path: { + type: GraphQLString, + description: + 'The path where the security.txt file was requested (e.g., /.well-known/security.txt or /security.txt).', + }, + url: { + type: GraphQLString, + description: 'The full URL used to fetch the security.txt file.', + }, + statusCode: { + type: GraphQLInt, + description: 'The HTTP status code returned when requesting the security.txt file.', + }, + fields: { + type: GraphQLJSONObject, + description: 'Parsed fields from the security.txt file as key-value pairs.', + }, + isValid: { + type: GraphQLBoolean, + description: 'Whether the security.txt file was found and successfully parsed.', + }, + error: { + type: GraphQLString, + description: 'Any errors encountered during fetching or parsing the security.txt file.', + }, + raw: { + type: GraphQLString, + description: 'The raw contents of the security.txt file, if available.', + }, + redirected: { + type: GraphQLBoolean, + description: 'Whether the request for security.txt was redirected.', + }, + redirectLocation: { + type: GraphQLString, + description: 'The location to which the request was redirected, if any.', + }, + redirectStatusCode: { + type: GraphQLInt, + description: 'The HTTP status code returned by any redirect encountered.', + }, }), }) diff --git a/api/src/web-scan/objects/web.js b/api/src/web-scan/objects/web.js index 77ec486e72..10e1ba540d 100644 --- a/api/src/web-scan/objects/web.js +++ b/api/src/web-scan/objects/web.js @@ -21,8 +21,8 @@ export const webType = new GraphQLObjectType({ results: { type: new GraphQLList(webScanType), description: `Results of the web scan at each IP address.`, - resolve: async ({ _id }, args, { loaders: { loadWebScansByWebId } }) => { - return await loadWebScansByWebId({ + resolve: async ({ _id }, args, { dataSources: { webScan } }) => { + return await webScan.getScansByWebId({ webId: _id, ...args, }) diff --git a/azure-defender-easm/add-domain-to-easm/Dockerfile b/azure-defender-easm/add-domain-to-easm/Dockerfile index 28f5d3abf3..314f443b13 100644 --- a/azure-defender-easm/add-domain-to-easm/Dockerfile +++ b/azure-defender-easm/add-domain-to-easm/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11.11-slim-bookworm AS python-builder +FROM python:3.14.3-alpine AS python-builder # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -6,13 +6,12 @@ ENV PYTHONWARNINGS ignore WORKDIR /working/install -RUN apt-get update && apt-get install -y --no-install-recommends \ - apt-utils \ +RUN apk add --no-cache \ python3 \ - python3-pip \ - python3-setuptools \ - python3-wheel \ - build-essential \ + py3-pip \ + py3-setuptools \ + py3-wheel \ + build-base \ python3-dev COPY requirements.txt /requirements.txt @@ -22,7 +21,7 @@ RUN pip3 install --prefix=/working/install -r /requirements.txt #=============================================================================================== #=============================================================================================== -FROM python:3.11.11-slim-bookworm +FROM python:3.14.3-alpine # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -36,7 +35,7 @@ COPY --from=python-builder /working/install/lib /usr/local/lib COPY service.py ./ COPY clients ./clients -RUN useradd -ms /bin/bash defender +RUN adduser -D defender USER defender CMD ["python3", "service.py"] diff --git a/azure-defender-easm/add-domain-to-easm/requirements.txt b/azure-defender-easm/add-domain-to-easm/requirements.txt index b5d325a76d..bc781deaa5 100644 --- a/azure-defender-easm/add-domain-to-easm/requirements.txt +++ b/azure-defender-easm/add-domain-to-easm/requirements.txt @@ -1,7 +1,7 @@ azure-identity==1.16.1 azure-defender-easm==1.0.0b1 azure-kusto-data==4.3.1 -python-dotenv==1.1.0 +python-dotenv==1.2.2 nats-py==2.6.0 -numpy==1.26.4 -pandas==2.2.2 \ No newline at end of file +numpy==2.4.4 +pandas==3.0.2 \ No newline at end of file diff --git a/azure-defender-easm/add-easm-assets-to-tracker/Dockerfile b/azure-defender-easm/add-easm-assets-to-tracker/Dockerfile index 6799316e91..007d38947f 100644 --- a/azure-defender-easm/add-easm-assets-to-tracker/Dockerfile +++ b/azure-defender-easm/add-easm-assets-to-tracker/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.5-slim-bookworm AS python-builder +FROM python:3.14.3-alpine AS python-builder # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -6,13 +6,12 @@ ENV PYTHONWARNINGS ignore WORKDIR /working/install -RUN apt-get update && apt-get install -y --no-install-recommends \ - apt-utils \ +RUN apk add --no-cache \ python3 \ - python3-pip \ - python3-setuptools \ - python3-wheel \ - build-essential \ + py3-pip \ + py3-setuptools \ + py3-wheel \ + build-base \ python3-dev COPY requirements.txt /requirements.txt @@ -22,7 +21,7 @@ RUN pip3 install --prefix=/working/install -r /requirements.txt #=============================================================================================== #=============================================================================================== -FROM python:3.12.5-slim-bookworm +FROM python:3.14.3-alpine # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -36,7 +35,7 @@ COPY --from=python-builder /working/install/lib /usr/local/lib COPY service.py ./ COPY clients ./clients -RUN useradd -ms /bin/bash defender +RUN adduser -D defender USER defender CMD ["python3", "service.py"] diff --git a/azure-defender-easm/add-easm-assets-to-tracker/requirements.txt b/azure-defender-easm/add-easm-assets-to-tracker/requirements.txt index c82e8a9fa6..1508ec1773 100644 --- a/azure-defender-easm/add-easm-assets-to-tracker/requirements.txt +++ b/azure-defender-easm/add-easm-assets-to-tracker/requirements.txt @@ -1,7 +1,7 @@ azure-kusto-data==4.3.1 -python-dotenv==1.0.0 -python-arango==7.3.4 +python-dotenv==1.2.2 +python-arango==8.3.1 nats-py==2.6.0 -numpy==1.26.4 -pandas==2.2.2 +numpy==2.4.4 +pandas==3.0.2 dnspython==2.6.1 \ No newline at end of file diff --git a/azure-defender-easm/import-easm-additional-findings/Dockerfile b/azure-defender-easm/import-easm-additional-findings/Dockerfile index 3d948e0d9f..1eaf2c1556 100644 --- a/azure-defender-easm/import-easm-additional-findings/Dockerfile +++ b/azure-defender-easm/import-easm-additional-findings/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.5-slim-bookworm AS python-builder +FROM python:3.14.3-alpine AS python-builder # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -6,13 +6,12 @@ ENV PYTHONWARNINGS ignore WORKDIR /working/install -RUN apt-get update && apt-get install -y --no-install-recommends \ - apt-utils \ +RUN apk add --no-cache \ python3 \ - python3-pip \ - python3-setuptools \ - python3-wheel \ - build-essential \ + py3-pip \ + py3-setuptools \ + py3-wheel \ + build-base \ python3-dev COPY requirements.txt /requirements.txt @@ -22,7 +21,7 @@ RUN pip3 install --prefix=/working/install -r /requirements.txt #=============================================================================================== #=============================================================================================== -FROM python:3.12.5-slim-bookworm +FROM python:3.14.3-alpine # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -36,7 +35,7 @@ COPY --from=python-builder /working/install/lib /usr/local/lib COPY service.py ./ COPY clients ./clients -RUN useradd -ms /bin/bash defender +RUN adduser -D defender USER defender CMD ["python3", "service.py"] diff --git a/azure-defender-easm/import-easm-additional-findings/clients/kusto_client.py b/azure-defender-easm/import-easm-additional-findings/clients/kusto_client.py index 24b940fa45..d7188964dc 100644 --- a/azure-defender-easm/import-easm-additional-findings/clients/kusto_client.py +++ b/azure-defender-easm/import-easm-additional-findings/clients/kusto_client.py @@ -78,12 +78,12 @@ def get_web_components_by_asset(asset, fetched_cves): cve for cve in wc["WebComponentCves"] if cve["Cve"] in top25 ] - componentVersions = wc["WebComponentVersion"].split(".", 2) + component_versions = wc["WebComponentVersion"].split(".", 2) # Assign confidence levels to each CVE for cve in wc["WebComponentCves"]: cve["ConfidenceLevel"] = "unknown" # if detected version includes patch, high confidence - if len(componentVersions) == 3: + if len(component_versions) == 3: cve["ConfidenceLevel"] = "high" else: # fetch affected versions of CVE @@ -94,9 +94,9 @@ def get_web_components_by_asset(asset, fetched_cves): try: start, end = get_version_range(cpe).values() # compare minor and major version nums - if len(componentVersions) == 2: - major = int(componentVersions[0]) - minor = int(componentVersions[1]) + if len(component_versions) == 2: + major = int(component_versions[0]) + minor = int(component_versions[1]) if start is not None: if major < int(start.split(".")[0]): continue @@ -107,8 +107,8 @@ def get_web_components_by_asset(asset, fetched_cves): cve["ConfidenceLevel"] = "high" elif minor == int(end.split(".")[1]): cve["ConfidenceLevel"] = "medium" - elif len(componentVersions) == 1: - major = int(componentVersions[0]) + elif len(component_versions) == 1: + major = int(component_versions[0]) if start is not None: if major < int(start.split(".")[0]): continue @@ -129,7 +129,7 @@ def fetch_cve_affected_versions(cve, comp_name, fetched_cves): try: return fetched_cves[cve] except KeyError: - logger.error(f"Data on {cve} has not been fetched yet") + logger.info(f"Data on {cve} has not been fetched yet. Attempting to fetch it.") res = {"status_code": 0} attempts = 1 @@ -154,9 +154,14 @@ def fetch_cve_affected_versions(cve, comp_name, fetched_cves): time.sleep(60) attempts += 1 except Exception as e: - print("Error:", e) + logger.error(f"Encountered problem while fetching cves for {cve}: {e}") return None + # Unable to fetch CVE data + logger.error(f"Unable to fetch data for CVE: {cve}") + fetched_cves[cve] = None + return None + def get_version_range(affected_versions): versions = {"start": None, "end": None} diff --git a/azure-defender-easm/import-easm-additional-findings/requirements.txt b/azure-defender-easm/import-easm-additional-findings/requirements.txt index e9b79fcc63..bf3821bcd8 100644 --- a/azure-defender-easm/import-easm-additional-findings/requirements.txt +++ b/azure-defender-easm/import-easm-additional-findings/requirements.txt @@ -1,5 +1,5 @@ azure-kusto-data==4.3.1 -python-dotenv==1.1.0 -python-arango==7.3.4 -numpy==1.26.4 -pandas==2.2.2 \ No newline at end of file +python-dotenv==1.2.2 +python-arango==8.3.1 +numpy==2.4.4 +pandas==3.0.2 \ No newline at end of file diff --git a/azure-defender-easm/label-known-easm-assets/Dockerfile b/azure-defender-easm/label-known-easm-assets/Dockerfile index 0b541d93ab..a3fa7adf2b 100644 --- a/azure-defender-easm/label-known-easm-assets/Dockerfile +++ b/azure-defender-easm/label-known-easm-assets/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11.11-slim-bookworm AS python-builder +FROM python:3.14.3-alpine AS python-builder # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -6,13 +6,12 @@ ENV PYTHONWARNINGS ignore WORKDIR /working/install -RUN apt-get update && apt-get install -y --no-install-recommends \ - apt-utils \ +RUN apk add --no-cache \ python3 \ - python3-pip \ - python3-setuptools \ - python3-wheel \ - build-essential \ + py3-pip \ + py3-setuptools \ + py3-wheel \ + build-base \ python3-dev COPY requirements.txt /requirements.txt @@ -22,7 +21,7 @@ RUN pip3 install --prefix=/working/install -r /requirements.txt #=============================================================================================== #=============================================================================================== -FROM python:3.11.11-slim-bookworm +FROM python:3.14.3-alpine # Copy local code to the container image. ENV PYTHONUNBUFFERED 1 @@ -36,7 +35,7 @@ COPY --from=python-builder /working/install/lib /usr/local/lib COPY service.py ./ COPY clients ./clients -RUN useradd -ms /bin/bash defender +RUN adduser -D defender USER defender CMD ["python3", "service.py"] diff --git a/azure-defender-easm/label-known-easm-assets/requirements.txt b/azure-defender-easm/label-known-easm-assets/requirements.txt index 7966c4c990..d9cf725d4c 100644 --- a/azure-defender-easm/label-known-easm-assets/requirements.txt +++ b/azure-defender-easm/label-known-easm-assets/requirements.txt @@ -1,7 +1,7 @@ azure-identity==1.16.1 azure-defender-easm==1.0.0b1 azure-kusto-data==4.3.1 -python-dotenv==1.1.0 -python-arango==7.3.4 -numpy==1.26.4 -pandas==2.2.2 \ No newline at end of file +python-dotenv==1.2.2 +python-arango==8.3.1 +numpy==2.4.4 +pandas==3.0.2 \ No newline at end of file diff --git a/database-migration/Dockerfile b/database-migration/Dockerfile index f8a42a19d9..a7dd9c919b 100644 --- a/database-migration/Dockerfile +++ b/database-migration/Dockerfile @@ -1,4 +1,4 @@ -FROM node:alpine +FROM node:25.3.0-alpine ENV NODE_ENV production diff --git a/database-migration/package-lock.json b/database-migration/package-lock.json index c85225687e..5a3668bf91 100644 --- a/database-migration/package-lock.json +++ b/database-migration/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "arango-tools": "^0.6.0", - "arangojs": "^8.8.1", + "arangojs": "^9.2.0", "dotenv-safe": "^8.2.0", "json-placeholder-replacer": "^1.0.35" }, @@ -116,11 +116,6 @@ "node": ">= 8" } }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -128,9 +123,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", - "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==" + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "dependencies": { + "undici-types": "~6.21.0" + } }, "node_modules/acorn": { "version": "8.8.1", @@ -251,18 +249,14 @@ } }, "node_modules/arangojs": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-8.8.1.tgz", - "integrity": "sha512-gVc5BF91nT27lB97mt+XxcGbw7yOhPIkZ0f5Nmq/ZPt1/iP62rDpH961XUyWdzj5m4H8lx2OF/O2AVefZoolXg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-9.2.0.tgz", + "integrity": "sha512-WIoFPCrBeuX1kBzGwue4t+jjYFW/ipto4ZO5s6e1v6dMsZE4I+d5Bid2glL+D5UeUJ6qGgqfe3KOAAW1t0Pc2A==", "dependencies": { - "@types/node": ">=14", - "multi-part": "^4.0.0", - "path-browserify": "^1.0.1", - "x3-linkedlist": "1.2.0", - "xhr": "^2.4.1" + "@types/node": "^20.11.26" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/argparse": { @@ -1103,22 +1097,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", - "dependencies": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1149,9 +1127,9 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "node_modules/fs.realpath": { @@ -1366,25 +1344,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -1432,7 +1391,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/internal-slot": { "version": "1.0.4", @@ -1763,18 +1723,6 @@ "node": ">= 0.6" } }, - "node_modules/mime-kind": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mime-kind/-/mime-kind-4.0.0.tgz", - "integrity": "sha512-qQvglvSpS5mABi30beNFd+uHKtKkxD3dxAmhi2e589XKx+WfVqhg5i5P5LBcVgwwv3BiDpNMBWrHqU+JexW4aA==", - "dependencies": { - "file-type": "^16.5.4", - "mime-types": "^2.1.24" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", @@ -1795,9 +1743,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -1821,18 +1769,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/multi-part": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multi-part/-/multi-part-4.0.0.tgz", - "integrity": "sha512-YT/CS0PAe62kT8EoQXcQj8yIcSu18HhYv0s6ShdAFsoFly3oV5QaxODnkj0u7zH0/RFyH47cdcMVpcGXliEFVA==", - "dependencies": { - "mime-kind": "^4.0.0", - "multi-part-lite": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/multi-part-lite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/multi-part-lite/-/multi-part-lite-1.0.0.tgz", @@ -1973,11 +1909,6 @@ "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" }, - "node_modules/path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2011,18 +1942,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2084,34 +2003,6 @@ } ] }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -2215,25 +2106,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -2299,14 +2171,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string.prototype.trimend": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", @@ -2368,22 +2232,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2414,22 +2262,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -2481,6 +2313,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -2490,11 +2327,6 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2655,11 +2487,6 @@ "fastq": "^1.6.0" } }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -2667,9 +2494,12 @@ "dev": true }, "@types/node": { - "version": "18.11.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", - "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==" + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "requires": { + "undici-types": "~6.21.0" + } }, "acorn": { "version": "8.8.1", @@ -2759,15 +2589,11 @@ } }, "arangojs": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-8.8.1.tgz", - "integrity": "sha512-gVc5BF91nT27lB97mt+XxcGbw7yOhPIkZ0f5Nmq/ZPt1/iP62rDpH961XUyWdzj5m4H8lx2OF/O2AVefZoolXg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/arangojs/-/arangojs-9.2.0.tgz", + "integrity": "sha512-WIoFPCrBeuX1kBzGwue4t+jjYFW/ipto4ZO5s6e1v6dMsZE4I+d5Bid2glL+D5UeUJ6qGgqfe3KOAAW1t0Pc2A==", "requires": { - "@types/node": ">=14", - "multi-part": "^4.0.0", - "path-browserify": "^1.0.1", - "x3-linkedlist": "1.2.0", - "xhr": "^2.4.1" + "@types/node": "^20.11.26" } }, "argparse": { @@ -3381,16 +3207,6 @@ "flat-cache": "^3.0.4" } }, - "file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", - "requires": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - } - }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3412,9 +3228,9 @@ } }, "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "fs.realpath": { @@ -3569,11 +3385,6 @@ "has-symbols": "^1.0.2" } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -3609,7 +3420,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "internal-slot": { "version": "1.0.4", @@ -3839,15 +3651,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, - "mime-kind": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mime-kind/-/mime-kind-4.0.0.tgz", - "integrity": "sha512-qQvglvSpS5mABi30beNFd+uHKtKkxD3dxAmhi2e589XKx+WfVqhg5i5P5LBcVgwwv3BiDpNMBWrHqU+JexW4aA==", - "requires": { - "file-type": "^16.5.4", - "mime-types": "^2.1.24" - } - }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", @@ -3865,9 +3668,9 @@ } }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -3885,15 +3688,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "multi-part": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multi-part/-/multi-part-4.0.0.tgz", - "integrity": "sha512-YT/CS0PAe62kT8EoQXcQj8yIcSu18HhYv0s6ShdAFsoFly3oV5QaxODnkj0u7zH0/RFyH47cdcMVpcGXliEFVA==", - "requires": { - "mime-kind": "^4.0.0", - "multi-part-lite": "^1.0.0" - } - }, "multi-part-lite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/multi-part-lite/-/multi-part-lite-1.0.0.tgz", @@ -3995,11 +3789,6 @@ "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" }, - "path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4024,11 +3813,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==" - }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4058,24 +3842,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "requires": { - "readable-stream": "^3.6.0" - } - }, "regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -4134,11 +3900,6 @@ "queue-microtask": "^1.2.2" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, "safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -4186,14 +3947,6 @@ "object-inspect": "^1.9.0" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, "string.prototype.trimend": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", @@ -4237,15 +3990,6 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, - "strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4267,15 +4011,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -4315,6 +4050,11 @@ "which-boxed-primitive": "^1.0.2" } }, + "undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4324,11 +4064,6 @@ "punycode": "^2.1.0" } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/database-migration/package.json b/database-migration/package.json index c2659b04ea..47fbdedad3 100644 --- a/database-migration/package.json +++ b/database-migration/package.json @@ -12,7 +12,7 @@ "license": "MIT", "dependencies": { "arango-tools": "^0.6.0", - "arangojs": "^8.8.1", + "arangojs": "^9.2.0", "dotenv-safe": "^8.2.0", "json-placeholder-replacer": "^1.0.35" }, diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 03d83f92a6..96809bf101 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20.16-alpine3.19 as build-env +FROM node:20.18.1-alpine3.19 as build-env WORKDIR /app @@ -7,7 +7,7 @@ COPY . . RUN npm ci && npm run build && npm prune --production -FROM gcr.io/distroless/nodejs20-debian12 +FROM node:20.18.1-alpine3.19 ENV HOST 0.0.0.0 ENV PORT 3000 diff --git a/frontend/cloudbuild.yaml b/frontend/cloudbuild.yaml index aa878b3e56..0c68fb760f 100644 --- a/frontend/cloudbuild.yaml +++ b/frontend/cloudbuild.yaml @@ -44,16 +44,16 @@ steps: args: ['run', 'compile'] - name: node:20.10.0-alpine - id: test + id: build-production-bundle dir: frontend entrypoint: npm - args: ['test'] + args: [ 'run', 'build' ] - name: node:20.10.0-alpine - id: build-production-bundle + id: test dir: frontend entrypoint: npm - args: ['run', 'build'] + args: ['test'] - name: 'gcr.io/cloud-builders/docker' id: generate-image-name diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 99b4443c4d..11774ffd9c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,7 +16,7 @@ "@chakra-ui/system": "^2.6.2", "@emotion/react": "^11.9.3", "@emotion/styled": "^11.9.3", - "@lingui/react": "^4.11.3", + "@lingui/react": "^5.9.3", "@visx/axis": "^2.17.0", "@visx/curve": "^3.3.0", "@visx/event": "^2.17.0", @@ -42,11 +42,10 @@ "intro.js-react": "^1.0.0", "isomorphic-unfetch": "^3.1.0", "json-2-csv": "^3.17.1", - "lodash-es": "^4.17.21", + "lodash-es": "^4.18.1", "make-plural": "^7.1.0", "prop-types": "^15.8.1", "react": "^18.2.0", - "react-diff-viewer-continued": "^3.2.6", "react-dom": "^18.2.0", "react-error-boundary": "^3.1.4", "react-joyride": "^2.8.2", @@ -64,10 +63,10 @@ "@babel/preset-react": "^7.18.6", "@graphql-tools/mock": "^8.7.0", "@graphql-tools/schema": "^10.0.0", - "@lingui/cli": "^5.4.0", - "@lingui/core": "^4.11.3", - "@lingui/loader": "^5.4.0", - "@lingui/macro": "^4.11.3", + "@lingui/cli": "^5.9.3", + "@lingui/core": "^5.9.3", + "@lingui/loader": "^5.9.3", + "@lingui/macro": "^5.9.3", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.4.0", "@testing-library/react-hooks": "^7.0.2", @@ -77,6 +76,7 @@ "babel-loader": "^8.2.5", "babel-plugin-macros": "^3.1.0", "clean-webpack-plugin": "^3.0.0", + "copy-webpack-plugin": "^14.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-import": "^2.26.0", @@ -98,7 +98,7 @@ "react-test-renderer": "^18.2.0", "source-map-loader": "^4.0.0", "supertest": "^6.2.3", - "webpack": "^5.94.0", + "webpack": "^5.105.0", "webpack-cli": "^4.10.0", "webpack-config-utils": "^2.3.1", "webpack-dev-server": "^4.9.2" @@ -3640,18 +3640,6 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" }, - "node_modules/@emotion/css": { - "version": "11.11.2", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.11.2.tgz", - "integrity": "sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew==", - "dependencies": { - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.2", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1" - } - }, "node_modules/@emotion/hash": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", @@ -4511,27 +4499,6 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -5088,7 +5055,8 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -5414,26 +5382,28 @@ "dev": true }, "node_modules/@lingui/babel-plugin-extract-messages": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-5.4.0.tgz", - "integrity": "sha512-hcxnDgtby6rfhRvLM0Q9IsJhIjNR9dnHrKLKgSHsc5dTA/RYajSYbsdUXECvOQN+whwgBoQtZb/hvALmBpmjQA==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-5.9.3.tgz", + "integrity": "sha512-zm6QHDILmhj8olgLL2zHQn18yFA5mf4hX7QzCr1OOI/e815I0IkecCYue1Ych+y+B+V0eLriiW8AcfpDRCQFFw==", "dev": true, + "license": "MIT", "engines": { "node": ">=20.0.0" } }, "node_modules/@lingui/babel-plugin-lingui-macro": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-lingui-macro/-/babel-plugin-lingui-macro-5.4.0.tgz", - "integrity": "sha512-VKRc/uQ4fyFJfRcBwaWDqDXNTj99IJzgAFX/P0keeTmLltW1nm/d367Ksku19JI1SDUo42p65YEuk3VxuXyQ3g==", - "dev": true, + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-lingui-macro/-/babel-plugin-lingui-macro-5.9.3.tgz", + "integrity": "sha512-fLMhBarRsuqBGOq2YuEoqOjEAV2VNezz/+f/Dn0vLFHF/kAjnFwTHb8pL8DRSIMsWG16mPrGnLpdROZBmJlFtA==", + "devOptional": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.20.12", "@babel/runtime": "^7.20.13", "@babel/types": "^7.20.7", - "@lingui/conf": "5.4.0", - "@lingui/core": "5.4.0", - "@lingui/message-utils": "5.4.0" + "@lingui/conf": "5.9.3", + "@lingui/core": "5.9.3", + "@lingui/message-utils": "5.9.3" }, "engines": { "node": ">=20.0.0" @@ -5447,305 +5417,153 @@ } } }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", + "node_modules/@lingui/cli": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-5.9.3.tgz", + "integrity": "sha512-KEE0J4eGlfpiLZ+l019qjraWfqfh5mUmQSJeTFw5PulO4v50zvxw5tDX8stpBzJ3QtgUQZlrMUh0OTGdURaAMg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" + "@babel/core": "^7.21.0", + "@babel/generator": "^7.21.1", + "@babel/parser": "^7.22.0", + "@babel/runtime": "^7.21.0", + "@babel/types": "^7.21.2", + "@lingui/babel-plugin-extract-messages": "5.9.3", + "@lingui/babel-plugin-lingui-macro": "5.9.3", + "@lingui/conf": "5.9.3", + "@lingui/core": "5.9.3", + "@lingui/format-po": "5.9.3", + "@lingui/message-utils": "5.9.3", + "chokidar": "3.5.1", + "cli-table": "^0.3.11", + "commander": "^10.0.0", + "convert-source-map": "^2.0.0", + "date-fns": "^3.6.0", + "esbuild": "^0.25.1", + "glob": "^11.0.0", + "micromatch": "^4.0.7", + "ms": "^2.1.3", + "normalize-path": "^3.0.0", + "ora": "^5.1.0", + "picocolors": "^1.1.1", + "pofile": "^1.1.4", + "pseudolocale": "^2.0.0", + "source-map": "^0.7.6", + "threads": "^1.7.0" }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/@lingui/core": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-5.4.0.tgz", - "integrity": "sha512-WtdAMkSU8Hbw0nOt+sZsNLJ2B8AO5EfZTpPIrzpKRiZ8RHZl/JOPzQlBLGbxKEoiPIiNcLnm3SZDNRJ16F/AYw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "5.4.0" + "bin": { + "lingui": "dist/lingui.js" }, "engines": { "node": ">=20.0.0" - }, - "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.0", - "babel-plugin-macros": "2 || 3" - }, - "peerDependenciesMeta": { - "@lingui/babel-plugin-lingui-macro": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } } }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/@lingui/message-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.4.0.tgz", - "integrity": "sha512-Ok++R55W3kvI8dN7itti0DmQatDLodOUJVuEDDhCydzpYJCurwc60hZCn/o/M2SI2+BCVlkTOCXGkdcrpJVS2Q==", - "bundleDependencies": [ - "@messageformat/date-skeleton" - ], + "node_modules/@lingui/cli/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "dependencies": { - "@messageformat/parser": "^5.0.0", - "js-sha256": "^0.10.1" - }, "engines": { - "node": ">=20.0.0" + "node": "18 || 20 || >=22" } }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@lingui/cli/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "18 || 20 || >=22" } }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/@lingui/cli/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@lingui/cli/node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "node_modules/@lingui/cli/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "node_modules/@lingui/cli/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, - "node_modules/@lingui/babel-plugin-lingui-macro/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@lingui/cli/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">= 12" } }, - "node_modules/@lingui/cli": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-5.4.0.tgz", - "integrity": "sha512-S/mWIsTc1ggx0GajoIftIVEiv5pQWuBK+ip/YMrJrvr/gVHEzja/cT4db5f8dwadWyZ/YfJuEnz22RSKqBrrKA==", - "dev": true, + "node_modules/@lingui/conf": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.9.3.tgz", + "integrity": "sha512-hVEoYHmO2A3XmFX4A5RuBgcoVBoM7Xgoqejeq25XELvesJj2s2T15F47TA5n3/S7iTqngd6n/8KxBli9TYwgqQ==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.21.0", - "@babel/generator": "^7.21.1", - "@babel/parser": "^7.22.0", - "@babel/runtime": "^7.21.0", - "@babel/types": "^7.21.2", - "@lingui/babel-plugin-extract-messages": "5.4.0", - "@lingui/babel-plugin-lingui-macro": "5.4.0", - "@lingui/conf": "5.4.0", - "@lingui/core": "5.4.0", - "@lingui/format-po": "5.4.0", - "@lingui/message-utils": "5.4.0", - "chokidar": "3.5.1", - "cli-table": "^0.3.11", - "commander": "^10.0.0", - "convert-source-map": "^2.0.0", - "date-fns": "^3.6.0", - "esbuild": "^0.25.1", - "glob": "^11.0.0", - "micromatch": "^4.0.7", - "normalize-path": "^3.0.0", - "ora": "^5.1.0", - "picocolors": "^1.1.1", - "pofile": "^1.1.4", - "pseudolocale": "^2.0.0", - "source-map": "^0.8.0-beta.0" - }, - "bin": { - "lingui": "dist/lingui.js" + "@babel/runtime": "^7.20.13", + "cosmiconfig": "^8.0.0", + "jest-validate": "^29.4.3", + "jiti": "^2.5.1", + "picocolors": "^1.1.1" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@lingui/cli/node_modules/@jest/types": { + "node_modules/@lingui/conf/node_modules/@jest/types": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -5758,77 +5576,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@lingui/cli/node_modules/@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@lingui/cli/node_modules/@lingui/core": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-5.4.0.tgz", - "integrity": "sha512-WtdAMkSU8Hbw0nOt+sZsNLJ2B8AO5EfZTpPIrzpKRiZ8RHZl/JOPzQlBLGbxKEoiPIiNcLnm3SZDNRJ16F/AYw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "5.4.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@lingui/babel-plugin-lingui-macro": "5.4.0", - "babel-plugin-macros": "2 || 3" - }, - "peerDependenciesMeta": { - "@lingui/babel-plugin-lingui-macro": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/@lingui/cli/node_modules/@lingui/message-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.4.0.tgz", - "integrity": "sha512-Ok++R55W3kvI8dN7itti0DmQatDLodOUJVuEDDhCydzpYJCurwc60hZCn/o/M2SI2+BCVlkTOCXGkdcrpJVS2Q==", - "bundleDependencies": [ - "@messageformat/date-skeleton" - ], - "dev": true, - "dependencies": { - "@messageformat/parser": "^5.0.0", - "js-sha256": "^0.10.1" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@lingui/cli/node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, + "node_modules/@lingui/conf/node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "devOptional": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, - "node_modules/@lingui/cli/node_modules/ansi-styles": { + "node_modules/@lingui/conf/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -5839,17 +5602,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@lingui/cli/node_modules/argparse": { + "node_modules/@lingui/conf/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "devOptional": true, + "license": "Python-2.0" }, - "node_modules/@lingui/cli/node_modules/chalk": { + "node_modules/@lingui/conf/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5861,11 +5626,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@lingui/cli/node_modules/color-convert": { + "node_modules/@lingui/conf/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -5873,23 +5639,19 @@ "node": ">=7.0.0" } }, - "node_modules/@lingui/cli/node_modules/color-name": { + "node_modules/@lingui/conf/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@lingui/cli/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "devOptional": true, + "license": "MIT" }, - "node_modules/@lingui/cli/node_modules/cosmiconfig": { + "node_modules/@lingui/conf/node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -5911,52 +5673,32 @@ } } }, - "node_modules/@lingui/cli/node_modules/glob": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", - "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@lingui/cli/node_modules/has-flag": { + "node_modules/@lingui/conf/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "devOptional": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/@lingui/cli/node_modules/jest-get-type": { + "node_modules/@lingui/conf/node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, + "devOptional": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@lingui/cli/node_modules/jest-validate": { + "node_modules/@lingui/conf/node_modules/jest-validate": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -5969,11 +5711,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@lingui/cli/node_modules/js-yaml": { + "node_modules/@lingui/conf/node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -5981,26 +5724,12 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@lingui/cli/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", - "dev": true, - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@lingui/cli/node_modules/pretty-format": { + "node_modules/@lingui/conf/node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -6010,11 +5739,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@lingui/cli/node_modules/pretty-format/node_modules/ansi-styles": { + "node_modules/@lingui/conf/node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "devOptional": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -6022,29 +5752,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@lingui/cli/node_modules/react-is": { + "node_modules/@lingui/conf/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "node_modules/@lingui/cli/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } + "devOptional": true, + "license": "MIT" }, - "node_modules/@lingui/cli/node_modules/supports-color": { + "node_modules/@lingui/conf/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "devOptional": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6052,334 +5772,327 @@ "node": ">=8" } }, - "node_modules/@lingui/cli/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/@lingui/cli/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "node_modules/@lingui/cli/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/@lingui/conf": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-4.11.3.tgz", - "integrity": "sha512-KwUJDrbzlZEXmlmqttpB/Sd9hiIo0sqccsZaYTHzW/uULZT9T11aw/f6RcPLCVJeSKazg/7dJhR1cKlxKzvjKA==", - "dev": true, + "node_modules/@lingui/core": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/core/-/core-5.9.3.tgz", + "integrity": "sha512-3b8LnDjx8POdQ6q6UKBe2DHynyQFCO66vm8/UPQnvlQowUk4Xdu5bK6oet11D9/vrSznrDDS+Qb5JVcNBUImgg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.13", - "chalk": "^4.1.0", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "lodash.get": "^4.4.2" + "@lingui/message-utils": "5.9.3" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.0.0" + }, + "peerDependencies": { + "@lingui/babel-plugin-lingui-macro": "5.9.3", + "babel-plugin-macros": "2 || 3" + }, + "peerDependenciesMeta": { + "@lingui/babel-plugin-lingui-macro": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } } }, - "node_modules/@lingui/conf/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "node_modules/@lingui/format-po": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-5.9.3.tgz", + "integrity": "sha512-+LMnhWl7EmXrdOv10gopE1g8w8vtPY5Fxk72OORrGQFVMGBIioz4BEnKrNdV1ek2M+GxoMZtnUs17KrJN5Jv9A==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "@lingui/conf": "5.9.3", + "@lingui/message-utils": "5.9.3", + "date-fns": "^3.6.0", + "pofile": "^1.1.4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lingui/conf/node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">=20.0.0" } }, - "node_modules/@lingui/conf/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@lingui/loader": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/loader/-/loader-5.9.3.tgz", + "integrity": "sha512-V+m8vfZ1doPSc26fPZa1zVso75nl70mgdz51OHGAvFfafyDqYasFHmBf5xihS58vy6LXuep3K19Ymf6TG6i5TQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "@babel/runtime": "^7.20.13", + "@lingui/cli": "5.9.3", + "@lingui/conf": "5.9.3" }, "engines": { - "node": ">=8" + "node": ">=20.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/@lingui/conf/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@lingui/conf/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@lingui/macro": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-5.9.3.tgz", + "integrity": "sha512-xWqJ+hpp5T+xmE++VYlcfMxrF48LpY5Ak9N/luibY9d0AqvyYZiiv7Xaq7E2eK69v9CJWx+6eXA6uPhC8gHY+Q==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@lingui/core": "5.9.3", + "@lingui/react": "5.9.3" }, "engines": { - "node": ">=10" + "node": ">=20.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@lingui/babel-plugin-lingui-macro": "5.9.3", + "babel-plugin-macros": "2 || 3" + }, + "peerDependenciesMeta": { + "@lingui/babel-plugin-lingui-macro": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } } }, - "node_modules/@lingui/conf/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@lingui/message-utils": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.9.3.tgz", + "integrity": "sha512-oAK7HA7lcQrzaEaM6G1T5RwwxJxaSKfG/IFIxpZIl49TSFQv+s9YPNgHnVi+d4DmterpXNxy9ZZ+NtckJx6u7g==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@messageformat/parser": "^5.0.0", + "js-sha256": "^0.10.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=20.0.0" } }, - "node_modules/@lingui/conf/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@lingui/conf/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, + "node_modules/@lingui/react": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/react/-/react-5.9.3.tgz", + "integrity": "sha512-aje78l3zGGZ3C75fiGhDVKyVALHfiKlYFjcOlZpgXY/JAVfFuZX+6wUGG9x1A8k7BfxrDy/ofHIBahPvNAqoKw==", + "license": "MIT", "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "@babel/runtime": "^7.20.13", + "@lingui/core": "5.9.3" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" + "node": ">=20.0.0" }, "peerDependencies": { - "typescript": ">=4.9.5" + "@lingui/babel-plugin-lingui-macro": "5.9.3", + "babel-plugin-macros": "2 || 3", + "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { - "typescript": { + "@lingui/babel-plugin-lingui-macro": { + "optional": true + }, + "babel-plugin-macros": { "optional": true } } }, - "node_modules/@lingui/conf/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node_modules/@messageformat/parser": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz", + "integrity": "sha512-jKlkls3Gewgw6qMjKZ9SFfHUpdzEVdovKFtW1qRhJ3WI4FW5R/NnGDqr8SDGz+krWDO3ki94boMmQvGke1HwUQ==", + "dependencies": { + "moo": "^0.5.1" } }, - "node_modules/@lingui/conf/node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", + "dev": true, + "optional": true + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "dev": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@lingui/conf/node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8" } }, - "node_modules/@lingui/conf/node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 8" } }, - "node_modules/@lingui/conf/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8" } }, - "node_modules/@lingui/conf/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", "dev": true, - "engines": { - "node": ">=10" - }, + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/popperjs" } }, - "node_modules/@lingui/conf/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "dev": true }, - "node_modules/@lingui/conf/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "dev": true + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" } }, - "node_modules/@lingui/core": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-4.11.3.tgz", - "integrity": "sha512-IjJxn0Kvzv+ICnGlMqn8wRIQLikCJVrolb1oyi6GqtbiuPiwKYeU0D6Hbe146lMaTN8juc3tOCBS+Fr02XqFIQ==", - "dependencies": { - "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "4.11.3", - "unraw": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0" - } + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true }, - "node_modules/@lingui/format-po": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-5.4.0.tgz", - "integrity": "sha512-zQ930if6pTXAT4fQzbVdqORNc9g4XNCB2LwQ4nhzm65acCHI/BVMnGXkeU5qWLdX5xXPRIxaJbUvhXWh3Shy3A==", - "dev": true, - "dependencies": { - "@lingui/conf": "5.4.0", - "@lingui/message-utils": "5.4.0", - "date-fns": "^3.6.0", - "pofile": "^1.1.4" - }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "dev": true + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "dev": true + }, + "node_modules/@remix-run/router": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" } }, - "node_modules/@lingui/format-po/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", + "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "type-detect": "4.0.8" } }, - "node_modules/@lingui/format-po/node_modules/@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", + "node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=20.0.0" + "@sinonjs/commons": "^1.7.0" } }, - "node_modules/@lingui/format-po/node_modules/@lingui/message-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.4.0.tgz", - "integrity": "sha512-Ok++R55W3kvI8dN7itti0DmQatDLodOUJVuEDDhCydzpYJCurwc60hZCn/o/M2SI2+BCVlkTOCXGkdcrpJVS2Q==", - "bundleDependencies": [ - "@messageformat/date-skeleton" - ], + "node_modules/@testing-library/dom": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.13.0.tgz", + "integrity": "sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==", "dev": true, "dependencies": { - "@messageformat/parser": "^5.0.0", - "js-sha256": "^0.10.1" + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@lingui/format-po/node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">=12" } }, - "node_modules/@lingui/format-po/node_modules/ansi-styles": { + "node_modules/@testing-library/dom/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -6389,21 +6102,12 @@ }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@lingui/format-po/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@lingui/format-po/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -6411,12 +6115,9 @@ }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@lingui/format-po/node_modules/color-convert": { + "node_modules/@testing-library/dom/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -6428,39 +6129,13 @@ "node": ">=7.0.0" } }, - "node_modules/@lingui/format-po/node_modules/color-name": { + "node_modules/@testing-library/dom/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@lingui/format-po/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@lingui/format-po/node_modules/has-flag": { + "node_modules/@testing-library/dom/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -6469,59 +6144,21 @@ "node": ">=8" } }, - "node_modules/@lingui/format-po/node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lingui/format-po/node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lingui/format-po/node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@lingui/format-po/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.3", + "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "react-is": "^17.0.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/@lingui/format-po/node_modules/pretty-format/node_modules/ansi-styles": { + "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", @@ -6533,13 +6170,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@lingui/format-po/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "node_modules/@lingui/format-po/node_modules/supports-color": { + "node_modules/@testing-library/dom/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", @@ -6551,66 +6188,29 @@ "node": ">=8" } }, - "node_modules/@lingui/loader": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/loader/-/loader-5.4.0.tgz", - "integrity": "sha512-iU5fnP6IvnaofTTov9PmePYPIm2xLgxruQY/z5LDZV+G0oo9RGER8HEF/1D0lSypHuNuLQZCncoOhnxF6XN81w==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.4.0", - "@lingui/conf": "5.4.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/@lingui/loader/node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@lingui/loader/node_modules/@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", + "node_modules/@testing-library/jest-dom": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", + "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" + "@adobe/css-tools": "^4.0.1", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" }, "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@lingui/loader/node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": ">=8", + "npm": ">=6", + "yarn": ">=1" } }, - "node_modules/@lingui/loader/node_modules/ansi-styles": { + "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", @@ -6620,34 +6220,22 @@ }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@lingui/loader/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@lingui/loader/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, - "node_modules/@lingui/loader/node_modules/color-convert": { + "node_modules/@testing-library/jest-dom/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", @@ -6659,39 +6247,13 @@ "node": ">=7.0.0" } }, - "node_modules/@lingui/loader/node_modules/color-name": { + "node_modules/@testing-library/jest-dom/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@lingui/loader/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@lingui/loader/node_modules/has-flag": { + "node_modules/@testing-library/jest-dom/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", @@ -6700,750 +6262,276 @@ "node": ">=8" } }, - "node_modules/@lingui/loader/node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/@lingui/loader/node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "node_modules/@testing-library/react": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", + "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", "dev": true, "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.5.0", + "@types/react-dom": "^18.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@lingui/loader/node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "node_modules/@testing-library/react-hooks": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-7.0.2.tgz", + "integrity": "sha512-dYxpz8u9m4q1TuzfcUApqi8iFfR6R0FaMbr2hjZJy1uC8z+bO/K4v8Gs9eogGKYQop7QsrBTFkv/BCF7MzD2Cg==", "dev": true, "dependencies": { - "argparse": "^2.0.1" + "@babel/runtime": "^7.12.5", + "@types/react": ">=16.9.0", + "@types/react-dom": ">=16.9.0", + "@types/react-test-renderer": ">=16.9.0", + "react-error-boundary": "^3.1.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0", + "react-test-renderer": ">=16.9.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-test-renderer": { + "optional": true + } } }, - "node_modules/@lingui/loader/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", "dev": true, "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@babel/runtime": "^7.12.5" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@lingui/loader/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 6" } }, - "node_modules/@lingui/loader/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "node_modules/@lingui/loader/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@types/accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "@types/node": "*" } }, - "node_modules/@lingui/macro": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-4.11.3.tgz", - "integrity": "sha512-D0me8ZRtH0ylSavhKZu0FYf5mJ1y6kDMMPjYVDyiT5ooOI/5jjv9LIAqrdYGCBygnwsxOG1dzDw6+3s5GTs+Bg==", + "node_modules/@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "node_modules/@types/aria-query": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz", + "integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", "dev": true, "dependencies": { - "@babel/runtime": "^7.20.13", - "@babel/types": "^7.20.7", - "@lingui/conf": "4.11.3", - "@lingui/core": "4.11.3", - "@lingui/message-utils": "4.11.3" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@lingui/react": "^4.0.0", - "babel-plugin-macros": "2 || 3" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/@lingui/message-utils": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-4.11.3.tgz", - "integrity": "sha512-ZSw3OoKbknOw3nSrqt194g2F8r0guKow9csb46zlL7zX/yOWCaj767wvSvMoglZtVvurfQs4NPv2cohYlWORNw==", + "node_modules/@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, "dependencies": { - "@messageformat/parser": "^5.0.0", - "js-sha256": "^0.10.1" - }, - "engines": { - "node": ">=16.0.0" + "@babel/types": "^7.0.0" } }, - "node_modules/@lingui/react": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/react/-/react-4.11.3.tgz", - "integrity": "sha512-FuorwDsz5zDpUNpyj7J8ZKqJrrVxOz1EtQ3aJGJsmnTtVO01N3nR3ckMzpYvZ71XXdDEvhUC9ihmiKbFvpaZ/w==", + "node_modules/@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.20.13", - "@lingui/core": "4.11.3" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/@messageformat/parser": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz", - "integrity": "sha512-jKlkls3Gewgw6qMjKZ9SFfHUpdzEVdovKFtW1qRhJ3WI4FW5R/NnGDqr8SDGz+krWDO3ki94boMmQvGke1HwUQ==", + "node_modules/@types/babel__traverse": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "dev": true, "dependencies": { - "moo": "^0.5.1" + "@babel/types": "^7.3.0" } }, - "node_modules/@nicolo-ribaudo/chokidar-2": { - "version": "2.1.8-no-fsevents.3", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", - "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", - "dev": true, - "optional": true - }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "dependencies": { + "@types/connect": "*", + "@types/node": "*" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" + "@types/node": "*" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", "dev": true, - "engines": { - "node": ">= 8" + "dependencies": { + "@types/node": "*" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "@types/express-serve-static-core": "*", + "@types/node": "*" } }, - "node_modules/@paralleldrive/cuid2": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", - "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", - "dev": true, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "node_modules/@types/d3-array": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", + "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==" + }, + "node_modules/@types/d3-color": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.5.tgz", + "integrity": "sha512-5sNP3DmtSnSozxcjqmzQKsDOuVJXZkceo1KJScDc1982kk/TS9mTPc6lpli1gTu1MIBF1YWutpHpjucNWcIj5g==" + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==" + }, + "node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", "dependencies": { - "@noble/hashes": "^1.1.5" + "@types/geojson": "*" } }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } + "node_modules/@types/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==" }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "dev": true + "node_modules/@types/d3-random": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-2.2.3.tgz", + "integrity": "sha512-Ghs4R3CcgJ3o6svszRzIH4b8PPYex/COo+rhhZjDAs+bVducXwjmVSi27WcDOaLLCBV2t3tfVH9bYXAL76IvQA==" }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true + "node_modules/@types/d3-shape": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz", + "integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==", + "dependencies": { + "@types/d3-path": "^1" + } }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "dev": true + "node_modules/@types/d3-time": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.4.tgz", + "integrity": "sha512-BTfLsxTeo7yFxI/haOOf1ZwJ6xKgQLT9dCp+EcmQv87Gox6X+oKl4mLKfO6fnWm3P22+A6DknMNEZany8ql2Rw==" }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "dev": true + "node_modules/@types/d3-time-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", + "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==" }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "@types/estree": "*", + "@types/json-schema": "*" } }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "dev": true + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "dev": true - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "dev": true - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "dev": true - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "dev": true - }, - "node_modules/@remix-run/router": { - "version": "1.23.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", - "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", - "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@testing-library/dom": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.13.0.tgz", - "integrity": "sha512-9VHgfIatKNXQNaZTtLnalIy0jNZzY35a4S3oi08YAt9Hv1VsfZ/DfA45lM8D/UhtHBGJ4/lGwp0PZkVndRkoOQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/dom/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "dev": true, - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@testing-library/react-hooks": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-7.0.2.tgz", - "integrity": "sha512-dYxpz8u9m4q1TuzfcUApqi8iFfR6R0FaMbr2hjZJy1uC8z+bO/K4v8Gs9eogGKYQop7QsrBTFkv/BCF7MzD2Cg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "@types/react": ">=16.9.0", - "@types/react-dom": ">=16.9.0", - "@types/react-test-renderer": ">=16.9.0", - "react-error-boundary": "^3.1.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0", - "react-test-renderer": ">=16.9.0" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-test-renderer": { - "optional": true - } - } - }, - "node_modules/@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/anymatch": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", - "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", - "dev": true - }, - "node_modules/@types/aria-query": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz", - "integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, - "node_modules/@types/d3-array": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", - "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==" - }, - "node_modules/@types/d3-color": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.4.5.tgz", - "integrity": "sha512-5sNP3DmtSnSozxcjqmzQKsDOuVJXZkceo1KJScDc1982kk/TS9mTPc6lpli1gTu1MIBF1YWutpHpjucNWcIj5g==" - }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", - "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==" - }, - "node_modules/@types/d3-format": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", - "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==" - }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ==" - }, - "node_modules/@types/d3-random": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-2.2.3.tgz", - "integrity": "sha512-Ghs4R3CcgJ3o6svszRzIH4b8PPYex/COo+rhhZjDAs+bVducXwjmVSi27WcDOaLLCBV2t3tfVH9bYXAL76IvQA==" - }, - "node_modules/@types/d3-shape": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.8.tgz", - "integrity": "sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg==", - "dependencies": { - "@types/d3-path": "^1" - } - }, - "node_modules/@types/d3-time": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.1.4.tgz", - "integrity": "sha512-BTfLsxTeo7yFxI/haOOf1ZwJ6xKgQLT9dCp+EcmQv87Gox6X+oKl4mLKfO6fnWm3P22+A6DknMNEZany8ql2Rw==" - }, - "node_modules/@types/d3-time-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", - "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==" - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true }, "node_modules/@types/express": { @@ -7512,13 +6600,13 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true + "devOptional": true }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -7527,7 +6615,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, + "devOptional": true, "dependencies": { "@types/istanbul-lib-report": "*" } @@ -7543,9 +6631,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { @@ -7581,7 +6669,7 @@ "version": "14.0.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.26.tgz", "integrity": "sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA==", - "dev": true + "devOptional": true }, "node_modules/@types/node-forge": { "version": "1.3.14", @@ -7808,7 +6896,7 @@ "version": "15.0.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", - "dev": true + "devOptional": true }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.62.0", @@ -8432,148 +7520,148 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -8716,9 +7804,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -8749,13 +7837,16 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, + "engines": { + "node": ">=10.13.0" + }, "peerDependencies": { - "acorn": "^8" + "acorn": "^8.14.0" } }, "node_modules/acorn-jsx": { @@ -9663,13 +8754,6 @@ "node": ">= 10.14.2" } }, - "node_modules/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "optional": true, - "peer": true - }, "node_modules/balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -9749,6 +8833,15 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "devOptional": true, + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -9910,9 +9003,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "devOptional": true, "funding": [ { @@ -9929,10 +9022,11 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -10073,7 +9167,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=10" }, @@ -10082,9 +9176,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001653", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", - "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", + "version": "1.0.30001768", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001768.tgz", + "integrity": "sha512-qY3aDRZC5nWPgHUgIB84WL+nySuo19wk0VJpp/XI9T34lrvkyhRvNVOFJOp2kxClQhiFBu+TaUSudf6oa3vkSA==", "devOptional": true, "funding": [ { @@ -10581,6 +9675,103 @@ "toggle-selection": "^1.0.6" } }, + "node_modules/copy-webpack-plugin": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-14.0.0.tgz", + "integrity": "sha512-3JLW90aBGeaTLpM7mYQKpnVdgsUZRExY55giiZgLuX/xTQRUs1dOCwbBnWnvY6Q6rfZoXMNwzOQJCSZPppfqXA==", + "dev": true, + "dependencies": { + "glob-parent": "^6.0.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^7.0.3", + "tinyglobby": "^0.2.12" + }, + "engines": { + "node": ">= 20.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/copy-webpack-plugin/node_modules/serialize-javascript": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", + "dev": true, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/core-js-compat": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", @@ -11176,6 +10367,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -11733,9 +10925,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/electron-to-chromium": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", - "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "devOptional": true }, "node_modules/emittery": { @@ -11780,13 +10972,13 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -11892,9 +11084,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true }, "node_modules/es-object-atoms": { @@ -11988,9 +11180,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "devOptional": true, "engines": { "node": ">=6" @@ -12631,6 +11823,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -13174,6 +12377,22 @@ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, "node_modules/fastest-levenshtein": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", @@ -13376,9 +12595,9 @@ } }, "node_modules/flatted": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", - "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "node_modules/focus-lock": { @@ -13398,9 +12617,9 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true, "funding": [ { @@ -14895,6 +14114,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-observable": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", + "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -15232,7 +14464,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==", - "devOptional": true + "dev": true }, "node_modules/jackspeak": { "version": "4.1.1", @@ -16930,12 +16162,13 @@ } }, "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "devOptional": true, + "license": "MIT", "bin": { - "jiti": "bin/jiti.js" + "jiti": "lib/jiti-cli.mjs" } }, "node_modules/js-sha256": { @@ -17178,7 +16411,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -17202,12 +16435,16 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "dev": true, "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/loader-utils": { @@ -17225,26 +16462,20 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==" }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -17514,11 +16745,6 @@ "node": ">= 4.0.0" } }, - "node_modules/memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" - }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -17628,9 +16854,9 @@ "dev": true }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -17826,9 +17052,9 @@ } }, "node_modules/node-forge": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", - "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", "dev": true, "engines": { "node": ">= 6.13.0" @@ -17881,9 +17107,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "devOptional": true }, "node_modules/nodemon": { @@ -18195,6 +17421,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/observable-fns": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", + "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==", + "dev": true, + "license": "MIT" + }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -18587,10 +17820,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==" }, "node_modules/path-type": { "version": "4.0.0", @@ -18606,9 +17838,9 @@ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "engines": { "node": ">=8.6" @@ -18663,7 +17895,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/pofile/-/pofile-1.1.4.tgz", "integrity": "sha512-r6Q21sKsY1AjTVVjOuU02VYKVNQGJNQHjTIvs4dEbeuuYfxgYk/DGD2mqqq4RDaVkwdSq0VEtmQUOPe/wH8X3g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/popmotion": { "version": "9.3.6", @@ -18905,10 +18138,9 @@ } }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", - "license": "BSD-3-Clause", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dependencies": { "side-channel": "^1.1.0" }, @@ -18945,15 +18177,6 @@ } ] }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -19043,33 +18266,6 @@ "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/react-diff-viewer-continued": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/react-diff-viewer-continued/-/react-diff-viewer-continued-3.2.6.tgz", - "integrity": "sha512-GrzyqQnjIMoej+jMjWvtVSsQqhXgzEGqpXlJ2dAGfOk7Q26qcm8Gu6xtI430PBUyZsERe8BJSQf+7VZZo8IBNQ==", - "dependencies": { - "@emotion/css": "^11.10.5", - "classnames": "^2.3.1", - "diff": "^5.1.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">= 8" - }, - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-diff-viewer-continued/node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -20183,15 +19379,6 @@ "node": ">= 0.8" } }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -21188,40 +20375,6 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, - "node_modules/subscriptions-transport-ws": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz", - "integrity": "sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==", - "optional": true, - "peer": true, - "dependencies": { - "backo2": "^1.0.2", - "eventemitter3": "^3.1.0", - "iterall": "^1.2.1", - "symbol-observable": "^1.0.4", - "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependencies": { - "graphql": "^15.7.2 || ^16.0.0" - } - }, - "node_modules/subscriptions-transport-ws/node_modules/eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", - "optional": true, - "peer": true - }, - "node_modules/subscriptions-transport-ws/node_modules/symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/superagent": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz", @@ -21417,12 +20570,16 @@ "dev": true }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/terminal-link": { @@ -21439,13 +20596,13 @@ } }, "node_modules/terser": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", - "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -21457,16 +20614,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", + "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -21490,15 +20646,50 @@ } } }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -21534,6 +20725,50 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/threads": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", + "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.1.0", + "debug": "^4.2.0", + "is-observable": "^2.1.0", + "observable-fns": "^0.6.1" + }, + "funding": { + "url": "https://github.com/andywer/threads.js?sponsor=1" + }, + "optionalDependencies": { + "tiny-worker": ">= 2" + } + }, + "node_modules/threads/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/threads/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", @@ -21556,6 +20791,62 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "node_modules/tiny-worker": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", + "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "esm": "^3.2.25" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -21851,7 +21142,7 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "peer": true, "bin": { @@ -21951,11 +21242,6 @@ "node": ">= 0.8" } }, - "node_modules/unraw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", - "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==" - }, "node_modules/unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -22011,9 +21297,9 @@ "dev": true }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "devOptional": true, "funding": [ { @@ -22030,8 +21316,8 @@ } ], "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -22241,9 +21527,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -22281,34 +21567,36 @@ } }, "node_modules/webpack": { - "version": "5.94.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", - "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "version": "5.105.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -22673,23 +21961,58 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "dev": true, "engines": { "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -22941,7 +22264,7 @@ "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8.3.0" }, @@ -23005,9 +22328,9 @@ "dev": true }, "node_modules/yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "engines": { "node": ">= 6" } @@ -25773,18 +25096,6 @@ } } }, - "@emotion/css": { - "version": "11.11.2", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.11.2.tgz", - "integrity": "sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew==", - "requires": { - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.2", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1" - } - }, "@emotion/hash": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", @@ -26300,21 +25611,6 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, - "@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true - }, - "@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "requires": { - "@isaacs/balanced-match": "^4.0.1" - } - }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -26453,858 +25749,14 @@ "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - } - }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" - } - }, - "@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", - "dev": true, - "requires": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - } - }, - "@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "node-notifier": "^8.0.0", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.27.8" - } - }, - "@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", - "dev": true, - "requires": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - } - }, - "@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@josephg/resolvable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@josephg/resolvable/-/resolvable-1.0.1.tgz", - "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "devOptional": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" - }, - "@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@juggle/resize-observer": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz", - "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==" - }, - "@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", - "dev": true - }, - "@lingui/babel-plugin-extract-messages": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-5.4.0.tgz", - "integrity": "sha512-hcxnDgtby6rfhRvLM0Q9IsJhIjNR9dnHrKLKgSHsc5dTA/RYajSYbsdUXECvOQN+whwgBoQtZb/hvALmBpmjQA==", - "dev": true - }, - "@lingui/babel-plugin-lingui-macro": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-lingui-macro/-/babel-plugin-lingui-macro-5.4.0.tgz", - "integrity": "sha512-VKRc/uQ4fyFJfRcBwaWDqDXNTj99IJzgAFX/P0keeTmLltW1nm/d367Ksku19JI1SDUo42p65YEuk3VxuXyQ3g==", - "dev": true, - "requires": { - "@babel/core": "^7.20.12", - "@babel/runtime": "^7.20.13", - "@babel/types": "^7.20.7", - "@lingui/conf": "5.4.0", - "@lingui/core": "5.4.0", - "@lingui/message-utils": "5.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", - "dev": true, - "requires": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" - } - }, - "@lingui/core": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-5.4.0.tgz", - "integrity": "sha512-WtdAMkSU8Hbw0nOt+sZsNLJ2B8AO5EfZTpPIrzpKRiZ8RHZl/JOPzQlBLGbxKEoiPIiNcLnm3SZDNRJ16F/AYw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "5.4.0" - } - }, - "@lingui/message-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.4.0.tgz", - "integrity": "sha512-Ok++R55W3kvI8dN7itti0DmQatDLodOUJVuEDDhCydzpYJCurwc60hZCn/o/M2SI2+BCVlkTOCXGkdcrpJVS2Q==", - "dev": true, - "requires": { - "@messageformat/parser": "^5.0.0", - "js-sha256": "^0.10.1" - } - }, - "@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "requires": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true - }, - "jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - } - }, - "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@lingui/cli": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-5.4.0.tgz", - "integrity": "sha512-S/mWIsTc1ggx0GajoIftIVEiv5pQWuBK+ip/YMrJrvr/gVHEzja/cT4db5f8dwadWyZ/YfJuEnz22RSKqBrrKA==", - "dev": true, - "requires": { - "@babel/core": "^7.21.0", - "@babel/generator": "^7.21.1", - "@babel/parser": "^7.22.0", - "@babel/runtime": "^7.21.0", - "@babel/types": "^7.21.2", - "@lingui/babel-plugin-extract-messages": "5.4.0", - "@lingui/babel-plugin-lingui-macro": "5.4.0", - "@lingui/conf": "5.4.0", - "@lingui/core": "5.4.0", - "@lingui/format-po": "5.4.0", - "@lingui/message-utils": "5.4.0", - "chokidar": "3.5.1", - "cli-table": "^0.3.11", - "commander": "^10.0.0", - "convert-source-map": "^2.0.0", - "date-fns": "^3.6.0", - "esbuild": "^0.25.1", - "glob": "^11.0.0", - "micromatch": "^4.0.7", - "normalize-path": "^3.0.0", - "ora": "^5.1.0", - "picocolors": "^1.1.1", - "pofile": "^1.1.4", - "pseudolocale": "^2.0.0", - "source-map": "^0.8.0-beta.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", - "dev": true, - "requires": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" - } - }, - "@lingui/core": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-5.4.0.tgz", - "integrity": "sha512-WtdAMkSU8Hbw0nOt+sZsNLJ2B8AO5EfZTpPIrzpKRiZ8RHZl/JOPzQlBLGbxKEoiPIiNcLnm3SZDNRJ16F/AYw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "5.4.0" - } - }, - "@lingui/message-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.4.0.tgz", - "integrity": "sha512-Ok++R55W3kvI8dN7itti0DmQatDLodOUJVuEDDhCydzpYJCurwc60hZCn/o/M2SI2+BCVlkTOCXGkdcrpJVS2Q==", - "dev": true, - "requires": { - "@messageformat/parser": "^5.0.0", - "js-sha256": "^0.10.1" - } - }, - "@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", + "slash": "^3.0.0" + }, + "dependencies": { "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -27314,16 +25766,10 @@ "color-convert": "^2.0.1" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -27345,114 +25791,106 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "requires": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - } - }, - "glob": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", - "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", - "dev": true, - "requires": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true - }, - "jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "has-flag": "^4.0.0" } - }, - "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + } + } + }, + "@jest/core": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "dev": true, + "requires": { + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "argparse": "^2.0.1" + "color-convert": "^2.0.1" } }, - "minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "@isaacs/brace-expansion": "^5.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "color-name": "~1.1.4" } }, - "react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { - "whatwg-url": "^7.0.0" + "glob": "^7.1.3" } }, "supports-color": { @@ -27463,72 +25901,79 @@ "requires": { "has-flag": "^4.0.0" } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } } } }, - "@lingui/conf": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-4.11.3.tgz", - "integrity": "sha512-KwUJDrbzlZEXmlmqttpB/Sd9hiIo0sqccsZaYTHzW/uULZT9T11aw/f6RcPLCVJeSKazg/7dJhR1cKlxKzvjKA==", + "@jest/environment": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", "dev": true, "requires": { - "@babel/runtime": "^7.20.13", - "chalk": "^4.1.0", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "lodash.get": "^4.4.2" + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2" + } + }, + "@jest/fake-timers": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", + "@types/node": "*", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + } + }, + "@jest/globals": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "dev": true, + "requires": { + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + } + }, + "@jest/reporters": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "node-notifier": "^8.0.0", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" }, "dependencies": { - "@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -27538,16 +25983,10 @@ "color-convert": "^2.0.1" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -27569,76 +26008,27 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "requires": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true - }, - "jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - } - }, - "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "requires": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" } }, - "react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "supports-color": { @@ -27652,74 +26042,152 @@ } } }, - "@lingui/core": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/core/-/core-4.11.3.tgz", - "integrity": "sha512-IjJxn0Kvzv+ICnGlMqn8wRIQLikCJVrolb1oyi6GqtbiuPiwKYeU0D6Hbe146lMaTN8juc3tOCBS+Fr02XqFIQ==", + "@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "devOptional": true, "requires": { - "@babel/runtime": "^7.20.13", - "@lingui/message-utils": "4.11.3", - "unraw": "^3.0.0" + "@sinclair/typebox": "^0.27.8" } }, - "@lingui/format-po": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-5.4.0.tgz", - "integrity": "sha512-zQ930if6pTXAT4fQzbVdqORNc9g4XNCB2LwQ4nhzm65acCHI/BVMnGXkeU5qWLdX5xXPRIxaJbUvhXWh3Shy3A==", + "@jest/source-map": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", "dev": true, "requires": { - "@lingui/conf": "5.4.0", - "@lingui/message-utils": "5.4.0", - "date-fns": "^3.6.0", - "pofile": "^1.1.4" + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" }, "dependencies": { - "@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "dev": true, + "requires": { + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "dev": true, + "requires": { + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + } + }, + "@jest/transform": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "color-convert": "^2.0.1" } }, - "@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "@lingui/message-utils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.4.0.tgz", - "integrity": "sha512-Ok++R55W3kvI8dN7itti0DmQatDLodOUJVuEDDhCydzpYJCurwc60hZCn/o/M2SI2+BCVlkTOCXGkdcrpJVS2Q==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "@messageformat/parser": "^5.0.0", - "js-sha256": "^0.10.1" + "color-name": "~1.1.4" } }, - "@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "has-flag": "^4.0.0" } - }, + } + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "dependencies": { "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -27729,16 +26197,10 @@ "color-convert": "^2.0.1" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -27760,105 +26222,228 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "requires": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true - }, - "jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "has-flag": "^4.0.0" } - }, - "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + } + } + }, + "@josephg/resolvable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@josephg/resolvable/-/resolvable-1.0.1.tgz", + "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "devOptional": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, "requires": { - "argparse": "^2.0.1" + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@juggle/resize-observer": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz", + "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==" + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@lingui/babel-plugin-extract-messages": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-5.9.3.tgz", + "integrity": "sha512-zm6QHDILmhj8olgLL2zHQn18yFA5mf4hX7QzCr1OOI/e815I0IkecCYue1Ych+y+B+V0eLriiW8AcfpDRCQFFw==", + "dev": true + }, + "@lingui/babel-plugin-lingui-macro": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-lingui-macro/-/babel-plugin-lingui-macro-5.9.3.tgz", + "integrity": "sha512-fLMhBarRsuqBGOq2YuEoqOjEAV2VNezz/+f/Dn0vLFHF/kAjnFwTHb8pL8DRSIMsWG16mPrGnLpdROZBmJlFtA==", + "devOptional": true, + "requires": { + "@babel/core": "^7.20.12", + "@babel/runtime": "^7.20.13", + "@babel/types": "^7.20.7", + "@lingui/conf": "5.9.3", + "@lingui/core": "5.9.3", + "@lingui/message-utils": "5.9.3" + } + }, + "@lingui/cli": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-5.9.3.tgz", + "integrity": "sha512-KEE0J4eGlfpiLZ+l019qjraWfqfh5mUmQSJeTFw5PulO4v50zvxw5tDX8stpBzJ3QtgUQZlrMUh0OTGdURaAMg==", + "dev": true, + "requires": { + "@babel/core": "^7.21.0", + "@babel/generator": "^7.21.1", + "@babel/parser": "^7.22.0", + "@babel/runtime": "^7.21.0", + "@babel/types": "^7.21.2", + "@lingui/babel-plugin-extract-messages": "5.9.3", + "@lingui/babel-plugin-lingui-macro": "5.9.3", + "@lingui/conf": "5.9.3", + "@lingui/core": "5.9.3", + "@lingui/format-po": "5.9.3", + "@lingui/message-utils": "5.9.3", + "chokidar": "3.5.1", + "cli-table": "^0.3.11", + "commander": "^10.0.0", + "convert-source-map": "^2.0.0", + "date-fns": "^3.6.0", + "esbuild": "^0.25.1", + "glob": "^11.0.0", + "micromatch": "^4.0.7", + "ms": "^2.1.3", + "normalize-path": "^3.0.0", + "ora": "^5.1.0", + "picocolors": "^1.1.1", + "pofile": "^1.1.4", + "pseudolocale": "^2.0.0", + "source-map": "^0.7.6", + "threads": "^1.7.0" + }, + "dependencies": { + "balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true }, - "pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "requires": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "balanced-match": "^4.0.2" } }, - "react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + } + }, + "minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "requires": { + "brace-expansion": "^5.0.5" } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true } } }, - "@lingui/loader": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/loader/-/loader-5.4.0.tgz", - "integrity": "sha512-iU5fnP6IvnaofTTov9PmePYPIm2xLgxruQY/z5LDZV+G0oo9RGER8HEF/1D0lSypHuNuLQZCncoOhnxF6XN81w==", - "dev": true, + "@lingui/conf": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.9.3.tgz", + "integrity": "sha512-hVEoYHmO2A3XmFX4A5RuBgcoVBoM7Xgoqejeq25XELvesJj2s2T15F47TA5n3/S7iTqngd6n/8KxBli9TYwgqQ==", + "devOptional": true, "requires": { "@babel/runtime": "^7.20.13", - "@lingui/cli": "5.4.0", - "@lingui/conf": "5.4.0" + "cosmiconfig": "^8.0.0", + "jest-validate": "^29.4.3", + "jiti": "^2.5.1", + "picocolors": "^1.1.1" }, "dependencies": { "@jest/types": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, + "devOptional": true, "requires": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -27868,24 +26453,11 @@ "chalk": "^4.0.0" } }, - "@lingui/conf": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-5.4.0.tgz", - "integrity": "sha512-S4YIWyyPpncTfilNzmvSrPUJ8lFKvOs/2+j4Lpzwj5Ue5DIpxB+2WnpNkfw3GsQl3ilPiFbo87R21XKLNzMF+Q==", - "dev": true, - "requires": { - "@babel/runtime": "^7.20.13", - "cosmiconfig": "^8.0.0", - "jest-validate": "^29.4.3", - "jiti": "^1.17.1", - "picocolors": "^1.1.1" - } - }, "@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "devOptional": true, "requires": { "@types/yargs-parser": "*" } @@ -27894,7 +26466,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "requires": { "color-convert": "^2.0.1" } @@ -27903,13 +26475,13 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "devOptional": true }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "devOptional": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -27919,7 +26491,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, "requires": { "color-name": "~1.1.4" } @@ -27928,13 +26500,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "devOptional": true }, "cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, + "devOptional": true, "requires": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -27946,19 +26518,19 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "devOptional": true }, "jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true + "devOptional": true }, "jest-validate": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, + "devOptional": true, "requires": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -27972,7 +26544,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "devOptional": true, "requires": { "argparse": "^2.0.1" } @@ -27981,7 +26553,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "devOptional": true, "requires": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -27992,7 +26564,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true + "devOptional": true } } }, @@ -28000,48 +26572,77 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "devOptional": true }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "devOptional": true, "requires": { "has-flag": "^4.0.0" } } } }, - "@lingui/macro": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-4.11.3.tgz", - "integrity": "sha512-D0me8ZRtH0ylSavhKZu0FYf5mJ1y6kDMMPjYVDyiT5ooOI/5jjv9LIAqrdYGCBygnwsxOG1dzDw6+3s5GTs+Bg==", + "@lingui/core": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/core/-/core-5.9.3.tgz", + "integrity": "sha512-3b8LnDjx8POdQ6q6UKBe2DHynyQFCO66vm8/UPQnvlQowUk4Xdu5bK6oet11D9/vrSznrDDS+Qb5JVcNBUImgg==", + "requires": { + "@babel/runtime": "^7.20.13", + "@lingui/message-utils": "5.9.3" + } + }, + "@lingui/format-po": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/format-po/-/format-po-5.9.3.tgz", + "integrity": "sha512-+LMnhWl7EmXrdOv10gopE1g8w8vtPY5Fxk72OORrGQFVMGBIioz4BEnKrNdV1ek2M+GxoMZtnUs17KrJN5Jv9A==", + "dev": true, + "requires": { + "@lingui/conf": "5.9.3", + "@lingui/message-utils": "5.9.3", + "date-fns": "^3.6.0", + "pofile": "^1.1.4" + } + }, + "@lingui/loader": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/loader/-/loader-5.9.3.tgz", + "integrity": "sha512-V+m8vfZ1doPSc26fPZa1zVso75nl70mgdz51OHGAvFfafyDqYasFHmBf5xihS58vy6LXuep3K19Ymf6TG6i5TQ==", "dev": true, "requires": { "@babel/runtime": "^7.20.13", - "@babel/types": "^7.20.7", - "@lingui/conf": "4.11.3", - "@lingui/core": "4.11.3", - "@lingui/message-utils": "4.11.3" + "@lingui/cli": "5.9.3", + "@lingui/conf": "5.9.3" + } + }, + "@lingui/macro": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-5.9.3.tgz", + "integrity": "sha512-xWqJ+hpp5T+xmE++VYlcfMxrF48LpY5Ak9N/luibY9d0AqvyYZiiv7Xaq7E2eK69v9CJWx+6eXA6uPhC8gHY+Q==", + "dev": true, + "requires": { + "@lingui/core": "5.9.3", + "@lingui/react": "5.9.3" } }, "@lingui/message-utils": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-4.11.3.tgz", - "integrity": "sha512-ZSw3OoKbknOw3nSrqt194g2F8r0guKow9csb46zlL7zX/yOWCaj767wvSvMoglZtVvurfQs4NPv2cohYlWORNw==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/message-utils/-/message-utils-5.9.3.tgz", + "integrity": "sha512-oAK7HA7lcQrzaEaM6G1T5RwwxJxaSKfG/IFIxpZIl49TSFQv+s9YPNgHnVi+d4DmterpXNxy9ZZ+NtckJx6u7g==", "requires": { "@messageformat/parser": "^5.0.0", "js-sha256": "^0.10.1" } }, "@lingui/react": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@lingui/react/-/react-4.11.3.tgz", - "integrity": "sha512-FuorwDsz5zDpUNpyj7J8ZKqJrrVxOz1EtQ3aJGJsmnTtVO01N3nR3ckMzpYvZ71XXdDEvhUC9ihmiKbFvpaZ/w==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@lingui/react/-/react-5.9.3.tgz", + "integrity": "sha512-aje78l3zGGZ3C75fiGhDVKyVALHfiKlYFjcOlZpgXY/JAVfFuZX+6wUGG9x1A8k7BfxrDy/ofHIBahPvNAqoKw==", "requires": { "@babel/runtime": "^7.20.13", - "@lingui/core": "4.11.3" + "@lingui/core": "5.9.3" } }, "@messageformat/parser": { @@ -28175,10 +26776,10 @@ "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==" }, "@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "devOptional": true }, "@sinonjs/commons": { "version": "1.8.2", @@ -28559,10 +27160,30 @@ "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==" }, + "@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, "@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true }, "@types/express": { @@ -28631,13 +27252,13 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true + "devOptional": true }, "@types/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, + "devOptional": true, "requires": { "@types/istanbul-lib-coverage": "*" } @@ -28646,7 +27267,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, + "devOptional": true, "requires": { "@types/istanbul-lib-report": "*" } @@ -28662,9 +27283,9 @@ } }, "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/json5": { @@ -28700,7 +27321,7 @@ "version": "14.0.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.26.tgz", "integrity": "sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA==", - "dev": true + "devOptional": true }, "@types/node-forge": { "version": "1.3.14", @@ -28924,7 +27545,7 @@ "version": "15.0.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", - "dev": true + "devOptional": true }, "@typescript-eslint/scope-manager": { "version": "5.62.0", @@ -29437,148 +28058,148 @@ } }, "@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "dev": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -29702,9 +28323,9 @@ } }, "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true }, "acorn-globals": { @@ -29725,10 +28346,10 @@ } } }, - "acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, "requires": {} }, @@ -30417,13 +29038,6 @@ "babel-preset-current-node-syntax": "^1.0.0" } }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "optional": true, - "peer": true - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -30490,6 +29104,12 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, + "baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "devOptional": true + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -30627,15 +29247,16 @@ "dev": true }, "browserslist": { - "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "devOptional": true, "requires": { - "caniuse-lite": "^1.0.30001646", - "electron-to-chromium": "^1.5.4", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" } }, "bser": { @@ -30748,12 +29369,12 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", - "dev": true + "devOptional": true }, "caniuse-lite": { - "version": "1.0.30001653", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", - "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", + "version": "1.0.30001768", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001768.tgz", + "integrity": "sha512-qY3aDRZC5nWPgHUgIB84WL+nySuo19wk0VJpp/XI9T34lrvkyhRvNVOFJOp2kxClQhiFBu+TaUSudf6oa3vkSA==", "devOptional": true }, "capture-exit": { @@ -31127,6 +29748,75 @@ "toggle-selection": "^1.0.6" } }, + "copy-webpack-plugin": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-14.0.0.tgz", + "integrity": "sha512-3JLW90aBGeaTLpM7mYQKpnVdgsUZRExY55giiZgLuX/xTQRUs1dOCwbBnWnvY6Q6rfZoXMNwzOQJCSZPppfqXA==", + "dev": true, + "requires": { + "glob-parent": "^6.0.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^7.0.3", + "tinyglobby": "^0.2.12" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + }, + "serialize-javascript": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", + "dev": true + } + } + }, "core-js-compat": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", @@ -32015,9 +30705,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", - "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "devOptional": true }, "emittery": { @@ -32053,13 +30743,13 @@ } }, "enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dev": true, "requires": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" } }, "enquirer": { @@ -32140,9 +30830,9 @@ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, "es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true }, "es-object-atoms": { @@ -32219,9 +30909,9 @@ } }, "escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "devOptional": true }, "escape-html": { @@ -32699,6 +31389,13 @@ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true, + "optional": true + }, "espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -33123,6 +31820,12 @@ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "dev": true }, + "fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true + }, "fastest-levenshtein": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", @@ -33283,9 +31986,9 @@ } }, "flatted": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", - "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true }, "focus-lock": { @@ -33304,9 +32007,9 @@ } }, "follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true }, "for-each": { @@ -34412,6 +33115,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-observable": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", + "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==", + "dev": true + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -34668,7 +33377,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==", - "devOptional": true + "dev": true }, "jackspeak": { "version": "4.1.1", @@ -36016,10 +34725,10 @@ } }, "jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "devOptional": true }, "js-sha256": { "version": "0.10.1", @@ -36214,7 +34923,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true + "devOptional": true }, "levn": { "version": "0.4.1", @@ -36232,9 +34941,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "dev": true }, "loader-utils": { @@ -36249,26 +34958,20 @@ } }, "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, "lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==" }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -36489,11 +35192,6 @@ "fs-monkey": "1.0.3" } }, - "memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" - }, "merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -36572,9 +35270,9 @@ "dev": true }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -36740,9 +35438,9 @@ } }, "node-forge": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", - "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", "dev": true }, "node-int64": { @@ -36785,9 +35483,9 @@ } }, "node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "devOptional": true }, "nodemon": { @@ -37020,6 +35718,12 @@ "es-abstract": "^1.19.1" } }, + "observable-fns": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", + "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==", + "dev": true + }, "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -37327,9 +36031,9 @@ } }, "path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==" }, "path-type": { "version": "4.0.0", @@ -37342,9 +36046,9 @@ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true }, "pify": { @@ -37574,9 +36278,9 @@ "dev": true }, "qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "requires": { "side-channel": "^1.1.0" } @@ -37593,15 +36297,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -37663,25 +36358,6 @@ "@babel/runtime": "^7.12.13" } }, - "react-diff-viewer-continued": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/react-diff-viewer-continued/-/react-diff-viewer-continued-3.2.6.tgz", - "integrity": "sha512-GrzyqQnjIMoej+jMjWvtVSsQqhXgzEGqpXlJ2dAGfOk7Q26qcm8Gu6xtI430PBUyZsERe8BJSQf+7VZZo8IBNQ==", - "requires": { - "@emotion/css": "^11.10.5", - "classnames": "^2.3.1", - "diff": "^5.1.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.8.1" - }, - "dependencies": { - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" - } - } - }, "react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -38546,15 +37222,6 @@ } } }, - "serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -39339,36 +38006,6 @@ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, - "subscriptions-transport-ws": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz", - "integrity": "sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==", - "optional": true, - "peer": true, - "requires": { - "backo2": "^1.0.2", - "eventemitter3": "^3.1.0", - "iterall": "^1.2.1", - "symbol-observable": "^1.0.4", - "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" - }, - "dependencies": { - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", - "optional": true, - "peer": true - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "optional": true, - "peer": true - } - } - }, "superagent": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz", @@ -39516,9 +38153,9 @@ } }, "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true }, "terminal-link": { @@ -39532,13 +38169,13 @@ } }, "terser": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", - "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -39552,27 +38189,54 @@ } }, "terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", + "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "terser": "^5.31.1" }, "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" } } } @@ -39594,6 +38258,36 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "threads": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", + "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", + "dev": true, + "requires": { + "callsites": "^3.1.0", + "debug": "^4.2.0", + "is-observable": "^2.1.0", + "observable-fns": "^0.6.1", + "tiny-worker": ">= 2" + }, + "dependencies": { + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, "throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", @@ -39616,6 +38310,41 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "tiny-worker": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", + "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", + "dev": true, + "optional": true, + "requires": { + "esm": "^3.2.25" + } + }, + "tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "requires": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "dependencies": { + "fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "requires": {} + }, + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true + } + } + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -39850,7 +38579,7 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, + "devOptional": true, "peer": true }, "unbox-primitive": { @@ -39921,11 +38650,6 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, - "unraw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unraw/-/unraw-3.0.0.tgz", - "integrity": "sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==" - }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -39973,13 +38697,13 @@ } }, "update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "devOptional": true, "requires": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" } }, "uri-js": { @@ -40141,9 +38865,9 @@ } }, "watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -40175,45 +38899,75 @@ "dev": true }, "webpack": { - "version": "5.94.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", - "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", - "dev": true, - "requires": { - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "version": "5.105.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" }, "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" } } } @@ -40447,9 +39201,9 @@ } }, "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "dev": true }, "websocket-driver": { @@ -40646,7 +39400,7 @@ "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "devOptional": true, + "dev": true, "requires": {} }, "xml-name-validator": { @@ -40692,9 +39446,9 @@ "dev": true }, "yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==" + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==" }, "yargs": { "version": "15.4.1", diff --git a/frontend/package.json b/frontend/package.json index 77eae25301..f25a87c314 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,9 +3,11 @@ "version": "0.1.0", "scripts": { "build": "webpack --env production --config webpack.config.js", + "build:dev": "webpack --env development --config webpack.config.js", "dev": "webpack serve --hot --env development", "webpack": "webpack", "start": "NODE_OPTIONS=--openssl-legacy-provider node index.js", + "start:dev": "NODE_ENV=development PORT=3300 HOST=127.0.0.1 node index.js", "test": "jest --silent", "test-coverage": "jest --coverage", "lint": "eslint src", @@ -22,7 +24,7 @@ "@chakra-ui/system": "^2.6.2", "@emotion/react": "^11.9.3", "@emotion/styled": "^11.9.3", - "@lingui/react": "^4.11.3", + "@lingui/react": "^5.9.3", "@visx/axis": "^2.17.0", "@visx/curve": "^3.3.0", "@visx/event": "^2.17.0", @@ -48,11 +50,10 @@ "intro.js-react": "^1.0.0", "isomorphic-unfetch": "^3.1.0", "json-2-csv": "^3.17.1", - "lodash-es": "^4.17.21", + "lodash-es": "^4.18.1", "make-plural": "^7.1.0", "prop-types": "^15.8.1", "react": "^18.2.0", - "react-diff-viewer-continued": "^3.2.6", "react-dom": "^18.2.0", "react-error-boundary": "^3.1.4", "react-joyride": "^2.8.2", @@ -70,10 +71,10 @@ "@babel/preset-react": "^7.18.6", "@graphql-tools/mock": "^8.7.0", "@graphql-tools/schema": "^10.0.0", - "@lingui/cli": "^5.4.0", - "@lingui/core": "^4.11.3", - "@lingui/loader": "^5.4.0", - "@lingui/macro": "^4.11.3", + "@lingui/cli": "^5.9.3", + "@lingui/core": "^5.9.3", + "@lingui/loader": "^5.9.3", + "@lingui/macro": "^5.9.3", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.4.0", "@testing-library/react-hooks": "^7.0.2", @@ -83,6 +84,7 @@ "babel-loader": "^8.2.5", "babel-plugin-macros": "^3.1.0", "clean-webpack-plugin": "^3.0.0", + "copy-webpack-plugin": "^14.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-import": "^2.26.0", @@ -104,7 +106,7 @@ "react-test-renderer": "^18.2.0", "source-map-loader": "^4.0.0", "supertest": "^6.2.3", - "webpack": "^5.94.0", + "webpack": "^5.105.0", "webpack-cli": "^4.10.0", "webpack-config-utils": "^2.3.1", "webpack-dev-server": "^4.9.2" diff --git a/frontend/src/Server.js b/frontend/src/Server.js index c8b4f9fee2..526c3edb3a 100644 --- a/frontend/src/Server.js +++ b/frontend/src/Server.js @@ -9,6 +9,23 @@ const staticPath = join(resolve(process.cwd()), 'public') const frenchHosts = process.env.FRENCH_HOSTS?.split(',') || [] const isProduction = process.env.TRACKER_PRODUCTION === 'true' +const baseHtml = fs.readFileSync(resolve(join('public', 'index.html')), 'utf8') + +const htmlByLanguage = { + en: baseHtml.replace( + '', + ``, + ), + fr: baseHtml.replace( + '', + ``, + ), +} + +function isHashed(filePath) { + return /\.[0-9a-f]{8,}\./i.test(filePath) +} + function Server() { const server = express() server.use(bodyParser.json()) @@ -24,19 +41,37 @@ function Server() { res.json({ status: 'ready' }) }) - server.use('/', express.static(staticPath, { maxage: '365d', index: false })) + server.use( + ['/manifest.json', '/robots.txt', '/favicon.ico'], + express.static(staticPath, { maxAge: '1d', index: false }), + ) + + server.use( + '/', + express.static(staticPath, { + index: false, + setHeaders(res, filePath) { + if (isHashed(filePath)) { + // filePath contains a hash? Cache for 1 year + res.setHeader('Cache-Control', 'public, max-age=31536000') + } else { + // file not already handled and does not contain a hash? Cache for 1d + res.setHeader('Cache-Control', 'public, max-age=86400') + } + }, + }), + ) server.get('*', (req, res) => { const host = req.hostname - const defaultLanguage = frenchHosts.includes(host) ? 'fr' : 'en' - let html = fs - .readFileSync(resolve(join('public', 'index.html')), 'utf8') - .replace( - '', - ``, - ) - res.send(html) + const lang = frenchHosts.includes(host) ? 'fr' : 'en' + + res.set('Cache-Control', 'no-cache') + + res.send(htmlByLanguage[lang]) }) + return server } + module.exports.Server = Server diff --git a/frontend/src/admin/AdminDomainCard.js b/frontend/src/admin/AdminDomainCard.js index 52554c922b..ae329088d1 100644 --- a/frontend/src/admin/AdminDomainCard.js +++ b/frontend/src/admin/AdminDomainCard.js @@ -1,9 +1,10 @@ import React from 'react' -import { t, Trans } from '@lingui/macro' -import { array, bool, string } from 'prop-types' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" +import { any, array, bool, object, string } from 'prop-types' import { Flex, ListItem, Tag, TagLabel, Text, Tooltip } from '@chakra-ui/react' -export function AdminDomainCard({ url, tags, assetState, isArchived, rcode, ...rest }) { +export function AdminDomainCard({ url, tags, assetState, isArchived, rcode, cvdEnrollment, children, ...rest }) { const assetStateLabels = { APPROVED: t`Approved`, DEPENDENCY: t`Dependency`, @@ -14,7 +15,8 @@ export function AdminDomainCard({ url, tags, assetState, isArchived, rcode, ...r return ( - + + {children} {url} @@ -37,6 +39,13 @@ export function AdminDomainCard({ url, tags, assetState, isArchived, rcode, ...r {assetStateLabels[assetState]} )} + {cvdEnrollment && cvdEnrollment.status !== 'NOT_ENROLLED' && ( + + + CVD {cvdEnrollment.status} + + + )} {rcode === 'NXDOMAIN' && ( NXDOMAIN @@ -60,4 +69,6 @@ AdminDomainCard.propTypes = { isArchived: bool, rcode: string, assetState: string, + children: any, + cvdEnrollment: object, } diff --git a/frontend/src/admin/AdminDomainList.js b/frontend/src/admin/AdminDomainList.js index c31c1bd451..834fd1c615 100644 --- a/frontend/src/admin/AdminDomainList.js +++ b/frontend/src/admin/AdminDomainList.js @@ -1,19 +1,15 @@ import React from 'react' -import { Divider, Flex, IconButton, Stack, Text } from '@chakra-ui/react' +import { IconButton, Text } from '@chakra-ui/react' import { ListOf } from '../components/ListOf' -import { Trans } from '@lingui/macro' +import { Trans } from "@lingui/react/macro" import { EditIcon, MinusIcon } from '@chakra-ui/icons' import { AdminDomainCard } from './AdminDomainCard' -import { ABTestVariant, ABTestWrapper } from '../app/ABTestWrapper' -import SubdomainDiscoveryButton from '../domains/SubdomainDiscoveryButton' import { array, bool, func, object, string } from 'prop-types' export function AdminDomainList({ nodes, verified, permission, - orgId, - orgSlug, i18n, setSelectedRemoveProps, removeOnOpen, @@ -29,61 +25,56 @@ export function AdminDomainList({ )} > - {({ id: domainId, domain, claimTags, archived, rcode, organizations, assetState }, index) => ( + {({ id: domainId, domain, claimTags, archived, rcode, organizations, assetState, cvdEnrollment }, index) => ( - {index === 0 && } - - - {(!verified || permission === 'SUPER_ADMIN' || rcode === 'NXDOMAIN') && ( - { - setSelectedRemoveProps({ domain, domainId, rcode }) - removeOnOpen() - }} - variant="danger" - px="2" - icon={} - aria-label={'Remove ' + domain} - /> - )} + + {(!verified || permission === 'SUPER_ADMIN' || rcode === 'NXDOMAIN') && ( { - setModalProps({ - archived, - mutation: 'update', - assetState, - tagInputList: claimTags, - editingDomainId: domainId, - editingDomainUrl: domain, - orgCount: organizations.totalCount, - }) - updateOnOpen() + setSelectedRemoveProps({ domain, domainId, rcode }) + removeOnOpen() }} - icon={} - aria-label={'Edit ' + domain} + variant="danger" + px="2" + icon={} + aria-label={'Remove ' + domain} + mr="1" /> - - { + setModalProps({ + archived, + mutation: 'update', + assetState, + tagInputList: claimTags, + editingDomainId: domainId, + editingDomainUrl: domain, + orgCount: organizations.totalCount, + cvdEnrollment, + permission, + }) + updateOnOpen() + }} + icon={} + aria-label={'Edit ' + domain} + mr="2" /> - - - - - - - + )} @@ -93,8 +84,6 @@ AdminDomainList.propTypes = { nodes: array.isRequired, verified: bool, permission: string, - orgId: string.isRequired, - orgSlug: string, i18n: object.isRequired, setSelectedRemoveProps: func.isRequired, removeOnOpen: func.isRequired, diff --git a/frontend/src/admin/AdminDomainModal.js b/frontend/src/admin/AdminDomainModal.js index e4a696a2c9..190620ac4e 100644 --- a/frontend/src/admin/AdminDomainModal.js +++ b/frontend/src/admin/AdminDomainModal.js @@ -1,5 +1,6 @@ import React, { useRef } from 'react' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { useLingui } from '@lingui/react' import { Badge, @@ -31,13 +32,31 @@ import { AddIcon, QuestionOutlineIcon } from '@chakra-ui/icons' import { array, bool, func, number, object, string } from 'prop-types' import { FieldArray, Formik } from 'formik' import { useMutation } from '@apollo/client' +import { ABTestVariant, ABTestWrapper } from '../app/ABTestWrapper' import { DomainField } from '../components/fields/DomainField' import { CREATE_DOMAIN, UPDATE_DOMAIN } from '../graphql/mutations' import withSuperAdmin from '../app/withSuperAdmin' +import { CvdEnrollmentForm } from './CvdEnrollmentForm' -export function AdminDomainModal({ isOpen, onClose, validationSchema, orgId, availableTags, ...props }) { - const { editingDomainId, editingDomainUrl, tagInputList, orgSlug, archived, assetState, mutation, orgCount } = props +export function AdminDomainModal({ + isOpen, + onClose, + validationSchema, + orgId, + availableTags, + editingDomainId, + editingDomainUrl, + tagInputList, + orgSlug, + archived, + assetState, + mutation, + orgCount, + cvdEnrollment, + permission, + ...rest +}) { const toast = useToast() const initialFocusRef = useRef() const { i18n } = useLingui() @@ -105,9 +124,7 @@ export function AdminDomainModal({ isOpen, onClose, validationSchema, orgId, ava onClose() toast({ title: i18n._(t`Domain updated`), - description: i18n._( - t`${editingDomainUrl} from ${orgSlug} successfully updated to ${updateDomain.result.domain}`, - ), + description: i18n._(t`${editingDomainUrl} from ${orgSlug} successfully updated.`), status: 'success', duration: 9000, isClosable: true, @@ -187,16 +204,16 @@ export function AdminDomainModal({ isOpen, onClose, validationSchema, orgId, ava } return ( - + { // Submit update detail mutation + const sanitizeCvdEnrollment = (enrollment) => { + if (!enrollment || typeof enrollment !== 'object') return enrollment + const { __typename, ...rest } = enrollment + return rest + } if (mutation === 'update') { await updateDomain({ variables: { @@ -213,6 +235,7 @@ export function AdminDomainModal({ isOpen, onClose, validationSchema, orgId, ava archived: values.archiveDomain, assetState: values.assetState, ignoreRua: values.ignoreRua, + cvdEnrollment: sanitizeCvdEnrollment(values.cvdEnrollment), }, }) } else if (mutation === 'create') { @@ -223,6 +246,7 @@ export function AdminDomainModal({ isOpen, onClose, validationSchema, orgId, ava tags: values.tags.map(({ tagId }) => tagId), archived: values.archiveDomain, assetState: values.assetState, + cvdEnrollment: sanitizeCvdEnrollment(values.cvdEnrollment), }, }) } @@ -306,6 +330,13 @@ export function AdminDomainModal({ isOpen, onClose, validationSchema, orgId, ava + + + + + + + + + + + CVD Enrollment Status + + + + + + + + + About Coordinated Vulnerability Disclosure (CVD) + + + + + 1. What is Coordinated Vulnerability Disclosure (CVD)? +
A structured process that allows security researchers to report vulnerabilities safely and + responsibly. It ensures findings are received, validated, and addressed in an organized way, + helping organizations fix issues before they can be exploited. +
+
+ + + + 2. Why enroll your domains? +
+ Enrolling your internet‑facing assets ensures researchers can report real vulnerabilities directly + to the Government of Canada through an approved and safe channel. This improves early detection, + reduces security risk, and strengthens your organization’s ability to respond quickly and + consistently. +
+
+ + + + 3. Which domains should you enroll? +
+ Enroll any public, internet‑facing domains or subdomains your organization owns—especially + production systems that deliver services or expose application functionality. Test or pre‑launch + environments may be excluded unless they are publicly accessible. +
+
+
+ + + +
+
+
+
+ +
+ + {values.cvdEnrollment.status !== 'NOT_ENROLLED' && ( + <> + + + + Description + + + + + + + + + Max Severity + + + + + + + + + Confidentiality Requirement + + + + + + + + + Integrity Requirement + + + + + + + + + Availability Requirement + + + + + + )} + + ) +} + +CvdEnrollmentForm.propTypes = { + values: object, + permission: string, + handleChange: func, +} diff --git a/frontend/src/admin/DomainTagsList.js b/frontend/src/admin/DomainTagsList.js index 398c88a65c..28f9ec0f39 100644 --- a/frontend/src/admin/DomainTagsList.js +++ b/frontend/src/admin/DomainTagsList.js @@ -6,7 +6,8 @@ import { EditIcon, PlusSquareIcon, ViewIcon, ViewOffIcon } from '@chakra-ui/icon import { LoadingMessage } from '../components/LoadingMessage' import { ErrorFallbackMessage } from '../components/ErrorFallbackMessage' import { TagForm } from './TagForm' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { string } from 'prop-types' export const DomainTagsList = ({ orgId, createOwnership }) => { diff --git a/frontend/src/admin/DomainUpdateList.js b/frontend/src/admin/DomainUpdateList.js index 754fc114c6..0c42f1eb2c 100644 --- a/frontend/src/admin/DomainUpdateList.js +++ b/frontend/src/admin/DomainUpdateList.js @@ -30,7 +30,8 @@ import { } from '@chakra-ui/react' import { useMutation } from '@apollo/client' import { array, func, number, string } from 'prop-types' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { UPDATE_DOMAINS_BY_DOMAIN_IDS, UPDATE_DOMAINS_BY_FILTERS } from '../graphql/mutations' export function DomainUpdateList({ orgId, domains, availableTags, filters, search, domainCount, resetToFirstPage }) { diff --git a/frontend/src/admin/OrganizationInformation.js b/frontend/src/admin/OrganizationInformation.js index 46dbd9f196..5ccf183c28 100644 --- a/frontend/src/admin/OrganizationInformation.js +++ b/frontend/src/admin/OrganizationInformation.js @@ -22,7 +22,8 @@ import { import { CheckCircleIcon, MinusIcon, EditIcon } from '@chakra-ui/icons' import { bool, func, string } from 'prop-types' import { useMutation, useQuery } from '@apollo/client' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { Formik } from 'formik' import { ORGANIZATION_INFORMATION } from '../graphql/queries' diff --git a/frontend/src/admin/SuperAdminUserList.js b/frontend/src/admin/SuperAdminUserList.js index 14acec41a6..c559bddbed 100644 --- a/frontend/src/admin/SuperAdminUserList.js +++ b/frontend/src/admin/SuperAdminUserList.js @@ -29,7 +29,8 @@ import { ErrorFallbackMessage } from '../components/ErrorFallbackMessage' import { RelayPaginationControls } from '../components/RelayPaginationControls' import { usePaginatedCollection } from '../utilities/usePaginatedCollection' import { useDebouncedFunction } from '../utilities/useDebouncedFunction' -import { Trans, t } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { CheckCircleIcon, EditIcon, MinusIcon } from '@chakra-ui/icons' import { SearchBox } from '../components/SearchBox' import { UserListModal } from './UserListModal' diff --git a/frontend/src/admin/TagForm.js b/frontend/src/admin/TagForm.js index 18dc2784a8..41603dc552 100644 --- a/frontend/src/admin/TagForm.js +++ b/frontend/src/admin/TagForm.js @@ -2,7 +2,8 @@ import React from 'react' import { Badge, Box, Button, Flex, FormLabel, Grid, Select, Switch, Text, useToast } from '@chakra-ui/react' import { useMutation } from '@apollo/client' import { CREATE_TAG, UPDATE_TAG } from '../graphql/mutations' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { Formik } from 'formik' import { FormField } from '../components/fields/FormField' import { getRequirement, schemaToValidation } from '../utilities/fieldRequirements' diff --git a/frontend/src/admin/UserList.js b/frontend/src/admin/UserList.js index 23f935ec5a..f8230ddcb9 100644 --- a/frontend/src/admin/UserList.js +++ b/frontend/src/admin/UserList.js @@ -8,12 +8,12 @@ import { Input, InputGroup, InputLeftElement, - Stack, Text, useDisclosure, } from '@chakra-ui/react' import { AddIcon, EditIcon, EmailIcon, MinusIcon } from '@chakra-ui/icons' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { string } from 'prop-types' import { UserListModal } from './UserListModal' @@ -85,45 +85,40 @@ export function UserList({ includePending, permission, orgSlug, orgId }) { ) : ( nodes.map(({ id, permission: userRole, user }) => { return ( - - - - { - setSelectedRemoveUser(user) - setMutation('remove') - onOpen() - }} - p={2} - m={0} - icon={} - /> - { - setEditingUserRole(userRole) - setEditingUserName(user.userName) - setMutation('update') - onOpen() - }} - p={2} - m={0} - icon={} - /> - - - - - + + { + setSelectedRemoveUser(user) + setMutation('remove') + onOpen() + }} + px="2" + mr="1" + icon={} + /> + { + setEditingUserRole(userRole) + setEditingUserName(user.userName) + setMutation('update') + onOpen() + }} + px="2" + mr="2" + icon={} + /> + ) }) ) diff --git a/frontend/src/admin/UserListModal.js b/frontend/src/admin/UserListModal.js index 425fec42a2..c74c4d0e08 100644 --- a/frontend/src/admin/UserListModal.js +++ b/frontend/src/admin/UserListModal.js @@ -14,7 +14,8 @@ import { Select, Text, } from '@chakra-ui/react' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { Formik } from 'formik' import { useMutation } from '@apollo/client' import { bool, func, string } from 'prop-types' diff --git a/frontend/src/admin/__tests__/AdminDomainCard.test.js b/frontend/src/admin/__tests__/AdminDomainCard.test.js index 49f3187ca2..46d1eb1d9f 100644 --- a/frontend/src/admin/__tests__/AdminDomainCard.test.js +++ b/frontend/src/admin/__tests__/AdminDomainCard.test.js @@ -3,24 +3,13 @@ import { render, waitFor } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom' import { List, theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' - +import { i18n } from '@lingui/core' import { AdminDomainCard } from '../AdminDomainCard' import { MockedProvider } from '@apollo/client/testing' import { IS_USER_SUPER_ADMIN } from '../../graphql/queries' import { UserVarProvider } from '../../utilities/userState' import { makeVar } from '@apollo/client' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: {}, - }, -}) - const mocks = [ { request: { diff --git a/frontend/src/admin/__tests__/AdminDomains.test.js b/frontend/src/admin/__tests__/AdminDomains.test.js index e88904dfaf..b9118938ee 100644 --- a/frontend/src/admin/__tests__/AdminDomains.test.js +++ b/frontend/src/admin/__tests__/AdminDomains.test.js @@ -3,30 +3,17 @@ import { fireEvent, render, waitFor } from '@testing-library/react' import { theme, ChakraProvider } from '@chakra-ui/react' import { MemoryRouter } from 'react-router-dom' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { MockedProvider } from '@apollo/client/testing' import { makeVar } from '@apollo/client' import userEvent from '@testing-library/user-event' -import { en } from 'make-plural/plurals' - import { AdminDomains } from '../AdminDomains' - import { createCache } from '../../client' import { UserVarProvider } from '../../utilities/userState' import { rawOrgDomainListData, rawOrgDomainListDataEmpty } from '../../fixtures/orgDomainListData' import { PAGINATED_ORG_DOMAINS_ADMIN_PAGE as FORWARD } from '../../graphql/queries' import { CREATE_DOMAIN, REMOVE_DOMAIN, UPDATE_DOMAIN } from '../../graphql/mutations' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - const mocks = [ { request: { @@ -231,6 +218,7 @@ describe('', () => { tags: [], archived: false, assetState: 'APPROVED', + cvdEnrollment: { status: 'NOT_ENROLLED' }, }, }, result: { @@ -327,6 +315,7 @@ describe('', () => { tags: [], archived: false, assetState: 'APPROVED', + cvdEnrollment: { status: 'NOT_ENROLLED' }, }, }, result: { @@ -503,6 +492,7 @@ describe('', () => { tags: [], archived: false, assetState: 'MONITOR_ONLY', + cvdEnrollment: { status: 'NOT_ENROLLED' }, }, }, result: { diff --git a/frontend/src/admin/__tests__/AdminPage.test.js b/frontend/src/admin/__tests__/AdminPage.test.js index d544206a0e..50ec096d92 100644 --- a/frontend/src/admin/__tests__/AdminPage.test.js +++ b/frontend/src/admin/__tests__/AdminPage.test.js @@ -1,15 +1,13 @@ import React from 'react' import { theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { MockedProvider } from '@apollo/client/testing' import AdminPage from '../AdminPage' import { waitFor, render } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' import userEvent from '@testing-library/user-event' - import { UserVarProvider } from '../../utilities/userState' import { TourProvider } from '../../userOnboarding/contexts/TourContext' @@ -20,16 +18,6 @@ import { PAGINATED_ORG_DOMAINS_ADMIN_PAGE, } from '../../graphql/queries' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - describe('', () => { it('shows a list of the users organizations', async () => { const { getByText } = render( diff --git a/frontend/src/admin/__tests__/AdminPanel.test.js b/frontend/src/admin/__tests__/AdminPanel.test.js index 2698b2b67b..c9ecfc7f06 100644 --- a/frontend/src/admin/__tests__/AdminPanel.test.js +++ b/frontend/src/admin/__tests__/AdminPanel.test.js @@ -2,14 +2,11 @@ import React from 'react' import { render, waitFor } from '@testing-library/react' import { theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { MockedProvider } from '@apollo/client/testing' import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' - import { AdminPanel } from '../AdminPanel' - import { createCache } from '../../client' import { UserVarProvider } from '../../utilities/userState' import { rawOrgDomainListData } from '../../fixtures/orgDomainListData' @@ -17,16 +14,6 @@ import { rawOrgUserListData } from '../../fixtures/orgUserListData' import { PAGINATED_ORG_AFFILIATIONS_ADMIN_PAGE, PAGINATED_ORG_DOMAINS_ADMIN_PAGE } from '../../graphql/queries' import { TourProvider } from '../../userOnboarding/contexts/TourContext' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - const mocks = [ { request: { diff --git a/frontend/src/admin/__tests__/AuditLogTable.test.js b/frontend/src/admin/__tests__/AuditLogTable.test.js index ac4d3dd677..d9860efe8d 100644 --- a/frontend/src/admin/__tests__/AuditLogTable.test.js +++ b/frontend/src/admin/__tests__/AuditLogTable.test.js @@ -1,28 +1,16 @@ import React from 'react' import { theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { MockedProvider } from '@apollo/client/testing' import { AuditLogTable } from '../AuditLogTable' import { waitFor, render } from '@testing-library/react' import { MemoryRouter } from 'react-router-dom' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' import userEvent from '@testing-library/user-event' - import { UserVarProvider } from '../../utilities/userState' import { AUDIT_LOGS } from '../../graphql/queries' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - describe('', () => { it('shows a table displaying activity logs from organizations', async () => { const { queryByText } = render( diff --git a/frontend/src/admin/__tests__/CvdEnrollmentForm.test.js b/frontend/src/admin/__tests__/CvdEnrollmentForm.test.js new file mode 100644 index 0000000000..b5e64e55e5 --- /dev/null +++ b/frontend/src/admin/__tests__/CvdEnrollmentForm.test.js @@ -0,0 +1,138 @@ +import React from 'react' +import { render, screen, fireEvent } from '@testing-library/react' +import { ChakraProvider, theme } from '@chakra-ui/react' +import { I18nProvider } from '@lingui/react' +import { i18n } from '@lingui/core' +import { CvdEnrollmentForm } from '../CvdEnrollmentForm' +import '@testing-library/jest-dom' + +describe('', () => { + const baseValues = { + cvdEnrollment: { + status: 'NOT_ENROLLED', + description: '', + maxSeverity: '', + confidentialityRequirement: '', + integrityRequirement: '', + availabilityRequirement: '', + }, + } + const handleChange = jest.fn() + + function renderForm(props) { + return render( + + + + + , + ) + } + + afterEach(() => { + jest.clearAllMocks() + }) + + it('renders the enrollment status select and info popover', () => { + renderForm({ values: baseValues, handleChange, permission: 'USER' }) + expect(screen.getAllByText(/CVD Enrollment Status/i)[0]).toBeInTheDocument() + expect(screen.getByText(/More Info/i)).toBeInTheDocument() + expect(screen.getByText(/Not Enrolled/i)).toBeInTheDocument() + }) + + it('shows Pending option for ADMIN permission', () => { + renderForm({ + values: { cvdEnrollment: { ...baseValues.cvdEnrollment, status: 'PENDING' } }, + handleChange, + permission: 'ADMIN', + }) + // Use queryByText with fallback for option + const pendingOption = screen.queryByText((content, element) => { + return element.tagName && element.tagName.toLowerCase() === 'option' && /Pending/i.test(content) + }) + expect(pendingOption).not.toBeNull() + }) + + it('shows Enrolled option for OWNER permission', () => { + renderForm({ + values: { cvdEnrollment: { ...baseValues.cvdEnrollment, status: 'ENROLLED' } }, + handleChange, + permission: 'OWNER', + }) + expect(screen.getAllByText(/Enrolled/i)[0]).toBeInTheDocument() + }) + + it('renders additional fields when status is not NOT_ENROLLED', () => { + renderForm({ + values: { + cvdEnrollment: { + ...baseValues.cvdEnrollment, + status: 'ENROLLED', + description: 'desc', + maxSeverity: 'HIGH', + confidentialityRequirement: 'LOW', + integrityRequirement: 'HIGH', + availabilityRequirement: 'LOW', + }, + }, + handleChange, + permission: 'OWNER', + }) + expect(screen.getByLabelText(/Description/i)).toBeInTheDocument() + expect(screen.getByLabelText(/Max Severity/i)).toBeInTheDocument() + expect(screen.getByLabelText(/Confidentiality Requirement/i)).toBeInTheDocument() + expect(screen.getByLabelText(/Integrity Requirement/i)).toBeInTheDocument() + expect(screen.getByLabelText(/Availability Requirement/i)).toBeInTheDocument() + }) + + it('calls handleChange when status is changed', () => { + renderForm({ values: baseValues, handleChange, permission: 'ADMIN' }) + // Use getByRole to select by combobox and name + const select = screen.getByRole('combobox', { name: /CVD Enrollment Status/i }) + fireEvent.change(select, { + target: { value: 'PENDING' }, + }) + expect(handleChange).toHaveBeenCalled() + }) + + it('calls handleChange for description input', () => { + renderForm({ + values: { + cvdEnrollment: { ...baseValues.cvdEnrollment, status: 'ENROLLED' }, + }, + handleChange, + permission: 'OWNER', + }) + fireEvent.change(screen.getByLabelText(/Description/i), { + target: { value: 'Test description' }, + }) + expect(handleChange).toHaveBeenCalled() + }) + + it('handles empty values for select fields', () => { + renderForm({ + values: { + cvdEnrollment: { + status: 'ENROLLED', + description: '', + maxSeverity: '', + confidentialityRequirement: '', + integrityRequirement: '', + availabilityRequirement: '', + }, + }, + handleChange, + permission: 'OWNER', + }) + expect(screen.getByLabelText(/Max Severity/i).value).toBe('') + expect(screen.getByLabelText(/Confidentiality Requirement/i).value).toBe('') + expect(screen.getByLabelText(/Integrity Requirement/i).value).toBe('') + expect(screen.getByLabelText(/Availability Requirement/i).value).toBe('') + }) + + it('does not render additional fields when status is NOT_ENROLLED', () => { + renderForm({ values: baseValues, handleChange, permission: 'USER' }) + expect(screen.queryByLabelText(/Description/i)).not.toBeInTheDocument() + expect(screen.queryByLabelText(/Max Severity/i)).not.toBeInTheDocument() + }) +}) diff --git a/frontend/src/admin/__tests__/DomainTagsList.test.js b/frontend/src/admin/__tests__/DomainTagsList.test.js index 41cd5fabeb..2b980e044c 100644 --- a/frontend/src/admin/__tests__/DomainTagsList.test.js +++ b/frontend/src/admin/__tests__/DomainTagsList.test.js @@ -2,9 +2,8 @@ import React from 'react' import { ChakraProvider, theme } from '@chakra-ui/react' import { MemoryRouter } from 'react-router-dom' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' import { render, screen, fireEvent, within } from '@testing-library/react' import { MockedProvider } from '@apollo/client/testing' import { DomainTagsList } from '../DomainTagsList' @@ -13,12 +12,6 @@ import { CREATE_TAG, UPDATE_TAG } from '../../graphql/mutations' import { UserVarProvider } from '../../utilities/userState' import '@testing-library/jest-dom' -const i18n = setupI18n({ - locale: 'en', - messages: { en: {} }, - localeData: { en: { plurals: en } }, -}) - jest.mock('@chakra-ui/react', () => { const actual = jest.requireActual('@chakra-ui/react') return { ...actual, useToast: () => jest.fn() } diff --git a/frontend/src/admin/__tests__/DomainUpdateList.test.js b/frontend/src/admin/__tests__/DomainUpdateList.test.js index 1c71bdaa76..17f3665127 100644 --- a/frontend/src/admin/__tests__/DomainUpdateList.test.js +++ b/frontend/src/admin/__tests__/DomainUpdateList.test.js @@ -2,26 +2,21 @@ import React from 'react' import { render, fireEvent, waitFor } from '@testing-library/react' import { ChakraProvider, theme } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { MockedProvider } from '@apollo/client/testing' -import { en } from 'make-plural/plurals' import { DomainUpdateList } from '../DomainUpdateList' import { UPDATE_DOMAINS_BY_DOMAIN_IDS, UPDATE_DOMAINS_BY_FILTERS } from '../../graphql/mutations' -const i18n = setupI18n({ - locale: 'en', - messages: { en: {} }, - localeData: { en: { plurals: en } }, -}) - const domains = [ { id: '1', domain: 'example.com', tags: ['tag1'] }, { id: '2', domain: 'test.com', tags: ['tag2'] }, ] + const availableTags = [ { label: 'Tag 1', tagId: 'tag1' }, { label: 'Tag 2', tagId: 'tag2' }, ] + const filters = [] const orgId = 'org-1' const search = '' diff --git a/frontend/src/admin/__tests__/SuperAdminUserList.test.js b/frontend/src/admin/__tests__/SuperAdminUserList.test.js index 4c76e990e4..75a2dccb48 100644 --- a/frontend/src/admin/__tests__/SuperAdminUserList.test.js +++ b/frontend/src/admin/__tests__/SuperAdminUserList.test.js @@ -4,27 +4,14 @@ import { MemoryRouter } from 'react-router-dom' import { theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' import { MockedProvider } from '@apollo/client/testing' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' - import { SuperAdminUserList } from '../SuperAdminUserList' - import { UserVarProvider } from '../../utilities/userState' import { createCache } from '../../client' import { FIND_MY_USERS } from '../../graphql/queries' import { UPDATE_USER_ROLE, REMOVE_USER_FROM_ORG } from '../../graphql/mutations' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - const saUserListMockData = { data: { findMyUsers: { diff --git a/frontend/src/admin/__tests__/TagForm.test.js b/frontend/src/admin/__tests__/TagForm.test.js index 19a1b71dcb..cc907b7c54 100644 --- a/frontend/src/admin/__tests__/TagForm.test.js +++ b/frontend/src/admin/__tests__/TagForm.test.js @@ -3,18 +3,11 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react' import { MockedProvider } from '@apollo/client/testing' import { ChakraProvider, theme } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' -import { en } from 'make-plural/plurals' +import { i18n } from '@lingui/core' import { TagForm } from '../TagForm' import { CREATE_TAG, UPDATE_TAG } from '../../graphql/mutations' import '@testing-library/jest-dom' -const i18n = setupI18n({ - locale: 'en', - messages: { en: {} }, - localeData: { en: { plurals: en } }, -}) - jest.mock('@chakra-ui/react', () => { const actual = jest.requireActual('@chakra-ui/react') return { diff --git a/frontend/src/admin/__tests__/UserList.test.js b/frontend/src/admin/__tests__/UserList.test.js index d59fcc6be4..418457bc2e 100644 --- a/frontend/src/admin/__tests__/UserList.test.js +++ b/frontend/src/admin/__tests__/UserList.test.js @@ -4,28 +4,15 @@ import { MemoryRouter } from 'react-router-dom' import { theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' import { MockedProvider } from '@apollo/client/testing' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' - import { UserList } from '../UserList' - import { UserVarProvider } from '../../utilities/userState' import { createCache } from '../../client' import { PAGINATED_ORG_AFFILIATIONS_ADMIN_PAGE as FORWARD } from '../../graphql/queries' import { UPDATE_USER_ROLE, INVITE_USER_TO_ORG, REMOVE_USER_FROM_ORG } from '../../graphql/mutations' import { rawOrgUserListData } from '../../fixtures/orgUserListData' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - const successMocks = [ { request: { @@ -142,11 +129,7 @@ describe('', () => { , ) - await waitFor(() => - expect( - getByText(rawOrgUserListData.findOrganizationBySlug.affiliations.edges[0].node.user.userName), - ).toBeInTheDocument(), - ) + await waitFor(() => expect(getByText(/test.user@email.com/i)).toBeInTheDocument()) }) describe('Admin profile userlist', () => { diff --git a/frontend/src/admin/__tests__/UserListModal.test.js b/frontend/src/admin/__tests__/UserListModal.test.js index 903f9ade0a..d21c830849 100644 --- a/frontend/src/admin/__tests__/UserListModal.test.js +++ b/frontend/src/admin/__tests__/UserListModal.test.js @@ -4,27 +4,14 @@ import { MemoryRouter } from 'react-router-dom' import { theme, ChakraProvider, useDisclosure } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' import { MockedProvider } from '@apollo/client/testing' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' - import { UserVarProvider } from '../../utilities/userState' import { createCache } from '../../client' import { UPDATE_USER_ROLE, INVITE_USER_TO_ORG, REMOVE_USER_FROM_ORG } from '../../graphql/mutations' import { UserListModal } from '../UserListModal' import userEvent from '@testing-library/user-event' import canada from '../../theme/canada' - -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - const orgId = 'test-id' const editingUserId = 'test-id' const editingUserName = 'test-username@email.com' diff --git a/frontend/src/app/App.js b/frontend/src/app/App.js index bd0a3bcac7..b0cf9ebc19 100644 --- a/frontend/src/app/App.js +++ b/frontend/src/app/App.js @@ -1,7 +1,8 @@ import React, { Suspense } from 'react' import { Link as RouteLink, Routes, Route, Navigate } from 'react-router-dom' import { AlertDescription, AlertTitle, Box, Code, CSSReset, Flex, Link, Skeleton, Text } from '@chakra-ui/react' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { Main } from './Main' import { TopBanner } from './TopBanner' diff --git a/frontend/src/app/ContactUsPage.js b/frontend/src/app/ContactUsPage.js index 1f09210f10..7ac31800b9 100644 --- a/frontend/src/app/ContactUsPage.js +++ b/frontend/src/app/ContactUsPage.js @@ -1,5 +1,5 @@ import React from 'react' -import { Trans } from '@lingui/macro' +import { Trans } from "@lingui/react/macro" import { Box, Divider, Heading, Button, Text, Link } from '@chakra-ui/react' import { Link as RouteLink } from 'react-router-dom' diff --git a/frontend/src/app/FloatingMenu.js b/frontend/src/app/FloatingMenu.js index 24dbeecfcb..e7efbce810 100644 --- a/frontend/src/app/FloatingMenu.js +++ b/frontend/src/app/FloatingMenu.js @@ -18,7 +18,8 @@ import { useDisclosure, useToast, } from '@chakra-ui/react' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { useLingui } from '@lingui/react' import { useMutation } from '@apollo/client' diff --git a/frontend/src/app/NotificationBanner.js b/frontend/src/app/NotificationBanner.js index 0e40f0cca7..c1d352009c 100644 --- a/frontend/src/app/NotificationBanner.js +++ b/frontend/src/app/NotificationBanner.js @@ -3,7 +3,8 @@ import { Flex, Box, CloseButton, Button, Alert, AlertIcon, useToast } from '@cha import { any, bool, oneOf, string } from 'prop-types' import { CloseIcon } from '@chakra-ui/icons' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { useMutation } from '@apollo/client' import { DISMISS_MESSAGE } from '../graphql/mutations' import { useUserVar } from '../utilities/userState' diff --git a/frontend/src/app/PageNotFound.js b/frontend/src/app/PageNotFound.js index 33a6f62a19..36b597cbd1 100644 --- a/frontend/src/app/PageNotFound.js +++ b/frontend/src/app/PageNotFound.js @@ -1,7 +1,7 @@ import React from 'react' import { Box, Divider, Heading, Stack, Text } from '@chakra-ui/react' import { WarningTwoIcon } from '@chakra-ui/icons' -import { Trans } from '@lingui/macro' +import { Trans } from "@lingui/react/macro" export default function PageNotFound() { return ( diff --git a/frontend/src/app/ReadGuidancePage.js b/frontend/src/app/ReadGuidancePage.js index c17f65d7b4..08f8137126 100644 --- a/frontend/src/app/ReadGuidancePage.js +++ b/frontend/src/app/ReadGuidancePage.js @@ -1,5 +1,5 @@ import React from 'react' -import { Trans } from '@lingui/macro' +import { Trans } from "@lingui/react/macro" import { Box, Heading, Text, Link, ListItem, OrderedList, UnorderedList, Divider, Code } from '@chakra-ui/react' import { useLingui } from '@lingui/react' diff --git a/frontend/src/app/RequestScanNotificationHandler.js b/frontend/src/app/RequestScanNotificationHandler.js index 93c753e563..736d2baa13 100644 --- a/frontend/src/app/RequestScanNotificationHandler.js +++ b/frontend/src/app/RequestScanNotificationHandler.js @@ -1,7 +1,7 @@ import React from 'react' import { useSubscription } from '@apollo/client' import { Box, useToast } from '@chakra-ui/react' -import { t } from '@lingui/macro' +import { t } from "@lingui/core/macro" import { node } from 'prop-types' import { useUserVar } from '../utilities/userState' diff --git a/frontend/src/app/SlideMessage.js b/frontend/src/app/SlideMessage.js index 77fc6cc0da..36de7aa7f5 100644 --- a/frontend/src/app/SlideMessage.js +++ b/frontend/src/app/SlideMessage.js @@ -1,7 +1,7 @@ import React from 'react' import { useLingui } from '@lingui/react' -import { Trans } from '@lingui/macro' +import { Trans } from "@lingui/react/macro" import sigEn from '../images/goc-header-logo-en.svg' import sigFr from '../images/goc-header-logo-fr.svg' diff --git a/frontend/src/app/TopBanner.js b/frontend/src/app/TopBanner.js index d2f1a70662..2df0ea448b 100644 --- a/frontend/src/app/TopBanner.js +++ b/frontend/src/app/TopBanner.js @@ -1,5 +1,6 @@ import React from 'react' -import { t, Trans } from '@lingui/macro' +import { t } from "@lingui/core/macro" +import { Trans } from "@lingui/react/macro" import { Box, Button, Flex, useToast, Image, Link, Skeleton } from '@chakra-ui/react' import { Link as RouteLink } from 'react-router-dom' import { useMutation } from '@apollo/client' diff --git a/frontend/src/app/__tests__/App.test.js b/frontend/src/app/__tests__/App.test.js index 4b2f339457..def4e881d6 100644 --- a/frontend/src/app/__tests__/App.test.js +++ b/frontend/src/app/__tests__/App.test.js @@ -4,27 +4,14 @@ import { MemoryRouter } from 'react-router-dom' import { cleanup, render, waitFor } from '@testing-library/react' import { MockedProvider } from '@apollo/client/testing' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' - import { App } from '../App' - import { UserVarProvider } from '../../utilities/userState' import { REFRESH_TOKENS } from '../../graphql/mutations' import { IS_LOGIN_REQUIRED } from '../../graphql/queries' import { TourProvider } from '../../userOnboarding/contexts/TourContext' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - const mocks = [ { request: { diff --git a/frontend/src/app/__tests__/ContactUsPage.test.js b/frontend/src/app/__tests__/ContactUsPage.test.js index 01bda95544..76ff46c917 100644 --- a/frontend/src/app/__tests__/ContactUsPage.test.js +++ b/frontend/src/app/__tests__/ContactUsPage.test.js @@ -4,24 +4,11 @@ import { MemoryRouter } from 'react-router-dom' import { cleanup, fireEvent, render, waitFor } from '@testing-library/react' import { MockedProvider } from '@apollo/client/testing' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { makeVar } from '@apollo/client' -import { en } from 'make-plural/plurals' - import ContactUsPage from '../ContactUsPage' - import { UserVarProvider } from '../../utilities/userState' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: { plurals: en }, - }, -}) - describe('', () => { afterEach(cleanup) @@ -68,9 +55,7 @@ describe('', () => { , ) - const button = await waitFor(() => - getByRole('link', { name: /Contact Us/i }), - ) + const button = await waitFor(() => getByRole('link', { name: /Contact Us/i })) await waitFor(() => { expect(button) fireEvent.click(button) diff --git a/frontend/src/app/__tests__/FloatingMenu.test.js b/frontend/src/app/__tests__/FloatingMenu.test.js index 91f5046f92..2339d3eaa5 100644 --- a/frontend/src/app/__tests__/FloatingMenu.test.js +++ b/frontend/src/app/__tests__/FloatingMenu.test.js @@ -2,27 +2,15 @@ import React from 'react' import { cleanup, render, waitFor } from '@testing-library/react' import { theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { createMemoryRouter, MemoryRouter, RouterProvider } from 'react-router-dom' import { fireEvent } from '@testing-library/dom' import { MockedProvider } from '@apollo/client/testing' import { makeVar } from '@apollo/client' - import { FloatingMenu } from '../FloatingMenu' - import { UserVarProvider } from '../../utilities/userState' import { SIGN_OUT } from '../../graphql/mutations' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: {}, - }, -}) - describe('', () => { it('renders', async () => { const { getByText } = render( diff --git a/frontend/src/app/__tests__/FloatingMenuLink.test.js b/frontend/src/app/__tests__/FloatingMenuLink.test.js index 21c40b8c8e..e074f34bee 100644 --- a/frontend/src/app/__tests__/FloatingMenuLink.test.js +++ b/frontend/src/app/__tests__/FloatingMenuLink.test.js @@ -2,25 +2,13 @@ import React from 'react' import { render, waitFor, fireEvent } from '@testing-library/react' import { theme, ChakraProvider } from '@chakra-ui/react' import { I18nProvider } from '@lingui/react' -import { setupI18n } from '@lingui/core' +import { i18n } from '@lingui/core' import { createMemoryRouter, MemoryRouter, RouterProvider } from 'react-router-dom' import { MockedProvider } from '@apollo/client/testing' import { makeVar } from '@apollo/client' - import { FloatingMenuLink } from '../FloatingMenuLink' - import { UserVarProvider } from '../../utilities/userState' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: {}, - }, -}) - describe('', () => { it('renders', async () => { const { getByText } = render( diff --git a/frontend/src/app/__tests__/Footer.test.js b/frontend/src/app/__tests__/Footer.test.js index 84f13808b7..435ebc568e 100644 --- a/frontend/src/app/__tests__/Footer.test.js +++ b/frontend/src/app/__tests__/Footer.test.js @@ -2,20 +2,9 @@ import React from 'react' import { I18nProvider } from '@lingui/react' import { theme, ChakraProvider } from '@chakra-ui/react' import { render } from '@testing-library/react' -import { setupI18n } from '@lingui/core' - +import { i18n } from '@lingui/core' import { Footer } from '../Footer' -const i18n = setupI18n({ - locale: 'en', - messages: { - en: {}, - }, - localeData: { - en: {}, - }, -}) - describe('