diff --git a/.devcontainer/updateContentCommand.sh b/.devcontainer/updateContentCommand.sh
index 4be12810ac..c08b35545b 100755
--- a/.devcontainer/updateContentCommand.sh
+++ b/.devcontainer/updateContentCommand.sh
@@ -3,10 +3,10 @@
export WEB_CONCURRENCY=2
invoke demo.build demo.start
sleep 120
-docker logs infrahub-infrahub-server-1
+docker logs infrahub-server-1
invoke demo.load-infra-schema
-docker logs infrahub-infrahub-server-1
+docker logs infrahub-server-1
sleep 90
-docker logs infrahub-infrahub-server-1
+docker logs infrahub-server-1
invoke demo.load-infra-data
invoke demo.stop
diff --git a/.github/workflows/ci-docker-image.yml b/.github/workflows/ci-docker-image.yml
index 39cd234552..c266d88e62 100644
--- a/.github/workflows/ci-docker-image.yml
+++ b/.github/workflows/ci-docker-image.yml
@@ -81,5 +81,3 @@ jobs:
platforms: ${{ inputs.platforms }}
tags: ${{ inputs.tags }}
labels: ${{ inputs.labels }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5db74683b4..a058fda216 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,15 +15,15 @@ concurrency:
env:
INFRAHUB_DB_USERNAME: neo4j
INFRAHUB_DB_PASSWORD: admin
- INFRAHUB_DB_ADDRESS: localhost
- INFRAHUB_DB_PORT: 7687
INFRAHUB_DB_PROTOCOL: bolt
- INFRAHUB_BROKER_ADDRESS: message-queue
INFRAHUB_LOG_LEVEL: CRITICAL
INFRAHUB_IMAGE_NAME: "opsmill/infrahub"
INFRAHUB_IMAGE_VER: "local"
+ INFRAHUB_SERVER_PORT: 0
+ INFRAHUB_DB_BACKUP_PORT: 0
+ VMAGENT_PORT: 0
PYTEST_XDIST_WORKER_COUNT: 4
- INFRAHUB_TEST_IN_DOCKER: 1
+ INFRAHUB_USE_TEST_CONTAINERS: 1
VALE_VERSION: "3.7.1"
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
METRICS_ENDPOINT: ${{ secrets.METRICS_ENDPOINT }}
@@ -90,8 +90,6 @@ jobs:
run: "yamllint -s ."
javascript-lint:
- if: needs.files-changed.outputs.javascript == 'true'
- needs: ["files-changed"]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
@@ -99,18 +97,13 @@ jobs:
uses: "actions/checkout@v4"
with:
submodules: true
- - name: Install NodeJS
- uses: actions/setup-node@v4
+ - name: Setup Biome
+ uses: biomejs/setup-biome@v2
with:
- node-version: 20
- cache: 'npm'
- cache-dependency-path: frontend/app/package-lock.json
- - name: Install frontend dependencies
- working-directory: ./frontend/app
- run: npm install
- - name: Run ESLint
+ version: 1.9.3
+ - name: Run Biome
working-directory: ./frontend/app
- run: npm run eslint
+ run: biome ci .
python-lint:
if: needs.files-changed.outputs.python == 'true'
@@ -123,11 +116,11 @@ jobs:
with:
submodules: true
- name: "Setup environment"
- run: "pip install ruff==0.5.0"
+ run: "pip install ruff==0.6.6"
- name: "Linting: ruff check"
- run: "ruff check ."
+ run: "ruff check . --exclude python_sdk"
- name: "Linting: ruff format"
- run: "ruff format --check --diff ."
+ run: "ruff format --check --diff --exclude python_sdk ."
markdown-lint:
if: needs.files-changed.outputs.documentation == 'true'
@@ -140,7 +133,7 @@ jobs:
with:
submodules: true
- name: "Linting: markdownlint"
- uses: DavidAnson/markdownlint-cli2-action@v16
+ uses: DavidAnson/markdownlint-cli2-action@v17
with:
config: .markdownlint.yaml
globs: |
@@ -241,24 +234,28 @@ jobs:
group: huge-runners
timeout-minutes: 45
env:
- INFRAHUB_DB_TYPE: memgraph
+ INFRAHUB_DB_TYPE: neo4j
steps:
- name: "Check out repository code"
uses: "actions/checkout@v4"
with:
submodules: true
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.12'
+ - name: "Setup git credentials"
+ run: "git config --global user.name 'Infrahub' && \
+ git config --global user.email 'infrahub@opsmill.com' && \
+ git config --global --add safe.directory '*' && \
+ git config --global credential.usehttppath true && \
+ git config --global credential.helper /usr/local/bin/infrahub-git-credential"
- name: "Setup Python environment"
- run: "pip install toml invoke"
- - name: "Set environment variables"
- run: echo INFRAHUB_BUILD_NAME=infrahub-${{ runner.name }} >> $GITHUB_ENV
- - name: "Set environment variables"
- run: echo INFRAHUB_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }} >> $GITHUB_ENV
- - name: "Clear docker environment"
- run: docker compose -p $INFRAHUB_BUILD_NAME down -v --remove-orphans --rmi local
- - name: "Build Test Image"
- run: "invoke dev.build"
- - name: "Pull External Docker Images"
- run: "invoke dev.pull"
+ run: |
+ poetry config virtualenvs.create false
+ pip install toml invoke
+ - name: "Install dependencies"
+ run: "poetry install --no-interaction --no-ansi"
- name: "Unit Tests"
run: "invoke backend.test-unit"
- name: "Coveralls : Unit Tests"
@@ -270,7 +267,7 @@ jobs:
flag-name: backend-unit
parallel: true
- name: Generate tracing spans
- if: always() && github.event.pull_request.head.repo.fork == false
+ if: always() && github.event.pull_request.head.repo.fork == false && github.actor != 'dependabot[bot]'
uses: inception-health/otel-upload-test-artifact-action@v1
with:
jobName: "backend-tests-unit"
@@ -296,22 +293,26 @@ jobs:
uses: "actions/checkout@v4"
with:
submodules: true
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.12'
+ - name: "Setup git credentials"
+ run: "git config --global user.name 'Infrahub' && \
+ git config --global user.email 'infrahub@opsmill.com' && \
+ git config --global --add safe.directory '*' && \
+ git config --global credential.usehttppath true && \
+ git config --global credential.helper /usr/local/bin/infrahub-git-credential"
- name: "Setup Python environment"
- run: "pip install toml invoke"
- - name: "Set environment variables"
- run: echo INFRAHUB_BUILD_NAME=infrahub-${{ runner.name }} >> $GITHUB_ENV
- - name: "Set environment variables"
- run: echo INFRAHUB_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }} >> $GITHUB_ENV
- - name: "Clear docker environment"
- run: docker compose -p $INFRAHUB_BUILD_NAME down -v --remove-orphans --rmi local
- - name: "Build Test Image"
- run: "invoke dev.build"
- - name: "Pull External Docker Images"
- run: "invoke dev.pull"
+ run: |
+ poetry config virtualenvs.create false
+ pip install toml invoke
+ - name: "Install dependencies"
+ run: "poetry install --no-interaction --no-ansi"
- name: "Mypy Tests"
- run: "invoke backend.mypy --docker"
+ run: "invoke backend.mypy"
- name: "Pylint Tests"
- run: "invoke backend.pylint --docker"
+ run: "invoke backend.pylint"
- name: "Integration Tests"
run: "invoke backend.test-integration"
- name: "Coveralls : Integration Tests"
@@ -323,7 +324,7 @@ jobs:
flag-name: backend-integration
parallel: true
- backend-tests-neo4j:
+ backend-tests-memgraph:
if: |
always() && !cancelled() &&
!contains(needs.*.result, 'failure') &&
@@ -337,18 +338,15 @@ jobs:
fail-fast: false
matrix:
include:
- - name: backend-tests-neo4j
- env:
- INFRAHUB_DB_TYPE: neo4j
- - name: backend-tests-nats
+ - name: backend-tests-unit-memgraph
env:
INFRAHUB_DB_TYPE: memgraph
- INFRAHUB_USE_NATS: 1
- INFRAHUB_BROKER_DRIVER: nats
- INFRAHUB_BROKER_PORT: 4222
- INFRAHUB_CACHE_DRIVER: nats
- INFRAHUB_CACHE_ADDRESS: message-queue
- INFRAHUB_CACHE_PORT: 4222
+ # - name: backend-tests-unit-nats
+ # env:
+ # INFRAHUB_DB_TYPE: memgraph
+ # INFRAHUB_USE_NATS: 1
+ # INFRAHUB_BROKER_DRIVER: nats
+ # INFRAHUB_CACHE_DRIVER: nats
name: ${{ matrix.name }}
env: ${{ matrix.env }}
steps:
@@ -356,18 +354,22 @@ jobs:
uses: "actions/checkout@v4"
with:
submodules: true
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.12'
+ - name: "Setup git credentials"
+ run: "git config --global user.name 'Infrahub' && \
+ git config --global user.email 'infrahub@opsmill.com' && \
+ git config --global --add safe.directory '*' && \
+ git config --global credential.usehttppath true && \
+ git config --global credential.helper /usr/local/bin/infrahub-git-credential"
- name: "Setup Python environment"
- run: "pip install toml invoke"
- - name: "Set environment variables"
- run: echo INFRAHUB_BUILD_NAME=infrahub-${{ runner.name }} >> $GITHUB_ENV
- - name: "Set environment variables"
- run: echo INFRAHUB_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }} >> $GITHUB_ENV
- - name: "Clear docker environment"
- run: docker compose -p $INFRAHUB_BUILD_NAME down -v --remove-orphans --rmi local
- - name: "Build Test Image"
- run: "invoke dev.build"
- - name: "Pull External Docker Images"
- run: "invoke dev.pull"
+ run: |
+ poetry config virtualenvs.create false
+ pip install toml invoke
+ - name: "Install dependencies"
+ run: "poetry install --no-interaction --no-ansi"
- name: "Unit Tests"
run: "invoke backend.test-unit"
@@ -554,15 +556,15 @@ jobs:
- name: E2E-testing-playwright
env:
INFRAHUB_DB_TYPE: neo4j
- - name: E2E-testing-playwright-nats
- env:
- INFRAHUB_DB_TYPE: neo4j
- INFRAHUB_USE_NATS: 1
- INFRAHUB_BROKER_DRIVER: nats
- INFRAHUB_BROKER_PORT: 4222
- INFRAHUB_CACHE_DRIVER: nats
- INFRAHUB_CACHE_ADDRESS: message-queue
- INFRAHUB_CACHE_PORT: 4222
+ # - name: E2E-testing-playwright-nats
+ # env:
+ # INFRAHUB_DB_TYPE: neo4j
+ # INFRAHUB_USE_NATS: 1
+ # INFRAHUB_BROKER_DRIVER: nats
+ # INFRAHUB_BROKER_PORT: 4222
+ # INFRAHUB_CACHE_DRIVER: nats
+ # INFRAHUB_CACHE_ADDRESS: message-queue
+ # INFRAHUB_CACHE_PORT: 4222
name: ${{ matrix.name }}
env: ${{ matrix.env }}
steps:
@@ -580,17 +582,11 @@ jobs:
- name: Install Invoke
run: pip install toml invoke
- - name: Select infrahub port
- run: echo "INFRAHUB_SERVER_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
- - name: Select infrahub db port
- run: echo "INFRAHUB_DB_BACKUP_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
- - name: Select vmagent port
- run: echo "VMAGENT_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
- name: Set job name
run: echo JOB_NAME="$GITHUB_JOB" >> $GITHUB_ENV
- name: Enable tracing
- if: github.event.pull_request.head.repo.fork == false
+ if: github.event.pull_request.head.repo.fork == false && github.actor != 'dependabot[bot]'
run: echo "INFRAHUB_TRACE_ENABLE=true" >> $GITHUB_ENV
- name: Set tracing configuration
run: echo "INFRAHUB_TRACE_INSECURE=false" >> $GITHUB_ENV
@@ -631,7 +627,9 @@ jobs:
run: invoke dev.infra-git-import dev.infra-git-create
- name: Set infrahub address
- run: echo "INFRAHUB_ADDRESS=http://localhost:${INFRAHUB_SERVER_PORT}" >> $GITHUB_ENV
+ run: |
+ PORT=$(docker compose -p $INFRAHUB_BUILD_NAME port server 8000 | cut -d: -f2)
+ echo "INFRAHUB_ADDRESS=http://localhost:${PORT}" >> $GITHUB_ENV
- name: Install frontend dependencies
run: npm install
@@ -657,11 +655,17 @@ jobs:
env:
INFRAHUB_MISC_RESPONSE_DELAY: 2
+ - name: Set infrahub address
+ if: needs.files-changed.outputs.e2e_tests == 'true'
+ run: |
+ PORT=$(docker compose -p $INFRAHUB_BUILD_NAME port server 8000 | cut -d: -f2)
+ echo "INFRAHUB_ADDRESS=http://localhost:${PORT}" >> $GITHUB_ENV
+
- name: Run Playwright tests
run: npm run ci:test:e2e
- name: Generate tracing spans
- if: always() && github.event.pull_request.head.repo.fork == false
+ if: always() && github.event.pull_request.head.repo.fork == false && github.actor != 'dependabot[bot]'
uses: inception-health/otel-upload-test-artifact-action@v1
with:
jobName: "E2E-testing-playwright"
@@ -683,15 +687,19 @@ jobs:
- name: Display server logs
if: always()
- run: docker logs "${INFRAHUB_BUILD_NAME}-infrahub-server-1"
+ run: docker logs "${INFRAHUB_BUILD_NAME}-server-1"
- - name: Display git 1 logs
+ - name: Display task worker 1 logs
if: always()
- run: docker logs "${INFRAHUB_BUILD_NAME}-infrahub-git-1"
+ run: docker logs "${INFRAHUB_BUILD_NAME}-task-worker-1"
- - name: Display git 2 logs
+ - name: Display task worker 2 logs
if: always()
- run: docker logs "${INFRAHUB_BUILD_NAME}-infrahub-git-2"
+ run: docker logs "${INFRAHUB_BUILD_NAME}-task-worker-2"
+
+ - name: Display task manager logs
+ if: always()
+ run: docker logs "${INFRAHUB_BUILD_NAME}-task-manager-1"
- name: Display database logs
if: always()
@@ -731,7 +739,7 @@ jobs:
runs-on:
group: huge-runners
env:
- INFRAHUB_DB_TYPE: memgraph
+ INFRAHUB_DB_TYPE: neo4j
steps:
- name: Check out repository code
uses: actions/checkout@v4
@@ -740,33 +748,19 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
- python-version: 3.12
- - name: "Setup environment"
+ python-version: '3.12'
+ - name: "Setup git credentials"
+ run: "git config --global user.name 'Infrahub' && \
+ git config --global user.email 'infrahub@opsmill.com' && \
+ git config --global --add safe.directory '*' && \
+ git config --global credential.usehttppath true && \
+ git config --global credential.helper /usr/local/bin/infrahub-git-credential"
+ - name: "Setup Python environment"
run: |
- pipx install poetry
- poetry config virtualenvs.prefer-active-python true
- pip install invoke toml
- - name: Set Version of Pydantic
- run: poetry add pydantic@^2
- - name: "Install Package"
- run: "poetry install"
-
- - name: Select infrahub db port
- run: echo "INFRAHUB_DB_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
-
- - name: "Set environment variables"
- run: echo INFRAHUB_BUILD_NAME=infrahub-${{ runner.name }} >> $GITHUB_ENV
- - name: "Set environment variables"
- run: echo INFRAHUB_IMAGE_VER=local-${{ runner.name }}-${{ github.sha }} >> $GITHUB_ENV
- - name: "Clear docker environment"
- run: docker compose -p $INFRAHUB_BUILD_NAME down -v --remove-orphans --rmi local
-
- - name: Create docker compose override
- run: mv development/docker-compose.dev-override-benchmark.yml development/docker-compose.dev-override.yml
-
- - name: Start dependencies
- run: invoke dev.deps
-
+ poetry config virtualenvs.create false
+ pip install toml invoke
+ - name: "Install dependencies"
+ run: "poetry install --no-interaction --no-ansi"
- name: Update PATH
run: "echo ~/.cargo/bin >> $GITHUB_PATH"
- name: Run benchmarks
@@ -774,8 +768,6 @@ jobs:
with:
token: ${{ secrets.CODSPEED_TOKEN }}
run: "poetry run pytest -v backend/tests/benchmark/ --codspeed"
- env:
- INFRAHUB_TEST_IN_DOCKER: "false"
# ------------------------------------------ Coverall Report ------------------------------------------
coverall-report:
needs:
diff --git a/.github/workflows/publish-dev-docker-image.yml b/.github/workflows/publish-dev-docker-image.yml
index 4929f771c9..b84b533f8e 100644
--- a/.github/workflows/publish-dev-docker-image.yml
+++ b/.github/workflows/publish-dev-docker-image.yml
@@ -62,8 +62,8 @@ jobs:
latest=false
- publish-docker-image:
- if: github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'cd/preview')
+ publish-docker-image-dispatch:
+ if: github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/ci-docker-image.yml
needs: meta_data
secrets: inherit
@@ -74,3 +74,16 @@ jobs:
tags: ${{needs.meta_data.outputs.tags}}
labels: ${{needs.meta_data.outputs.labels}}
platforms: ${{ inputs.platforms }}
+
+ publish-docker-image-pr:
+ if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'cd/preview')
+ uses: ./.github/workflows/ci-docker-image.yml
+ needs: meta_data
+ secrets: inherit
+ with:
+ publish: true
+ version: dev-${{ needs.meta_data.outputs.short_ref }}
+ ref: ${{ needs.meta_data.outputs.ref }}
+ tags: ${{ needs.meta_data.outputs.tags }}
+ labels: ${{ needs.meta_data.outputs.labels }}
+ platforms: "linux/amd64"
diff --git a/.github/workflows/scale-tests.yml b/.github/workflows/scale-tests.yml
index d2eb603291..7f876f096d 100644
--- a/.github/workflows/scale-tests.yml
+++ b/.github/workflows/scale-tests.yml
@@ -26,6 +26,9 @@ env:
INFRAHUB_LOG_LEVEL: CRITICAL
INFRAHUB_IMAGE_NAME: "opsmill/infrahub"
INFRAHUB_IMAGE_VER: "local"
+ INFRAHUB_SERVER_PORT: 0
+ INFRAHUB_DB_BACKUP_PORT: 0
+ VMAGENT_PORT: 0
jobs:
scale-tests:
@@ -160,16 +163,10 @@ jobs:
- name: "Clear docker environment"
run: docker compose -p $INFRAHUB_BUILD_NAME down -v --remove-orphans --rmi local
- - name: Select infrahub port
- run: echo "INFRAHUB_SERVER_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
- name: Set INFRAHUB_URL
- run: echo "INFRAHUB_URL=http://localhost:${INFRAHUB_SERVER_PORT}" >> $GITHUB_ENV
- - name: Select infrahub db port
- run: echo "INFRAHUB_DB_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
- - name: Select infrahub db port
- run: echo "INFRAHUB_DB_BACKUP_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
- - name: Select vmagent port
- run: echo "VMAGENT_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
+ run: |
+ PORT=$(docker compose -p $INFRAHUB_BUILD_NAME port infrahub-server 8000 | cut -d: -f2)
+ echo "INFRAHUB_URL=http://localhost:${PORT}" >> $GITHUB_ENV
- name: Set job name
run: echo "JOB_NAME=${{ matrix.name }}" >> $GITHUB_ENV
@@ -190,7 +187,7 @@ jobs:
run: 'echo "https://grafana-prod.tailc018d.ts.net/d/ebf7ec72-db79-4fb7-9b46-4621ca9c407a/scale-tests?orgId=1&var-run_id=$GITHUB_RUN_ID&var-job=${JOB_NAME// /%20}&var-stage=test&var-node_amount=${{ matrix.node-amount }}&var-attrs_amount=${{ matrix.attrs-amount }}&var-rels_amount=${{ matrix.rels-amount }}&var-runner=$INFRAHUB_BUILD_NAME&from=$TEST_START_TIME&to=$(date +%s)000"'
- name: Display server logs
if: always()
- run: docker logs "${INFRAHUB_BUILD_NAME}-infrahub-server-1"
+ run: docker logs "${INFRAHUB_BUILD_NAME}-server-1"
- name: "Destroy scale environment"
if: always()
run: "invoke backend.test-scale-env-destroy"
diff --git a/.github/workflows/version-upgrade.yml b/.github/workflows/version-upgrade.yml
index 8bbb19b194..9268895b25 100644
--- a/.github/workflows/version-upgrade.yml
+++ b/.github/workflows/version-upgrade.yml
@@ -26,6 +26,7 @@ env:
INFRAHUB_LOG_LEVEL: CRITICAL
INFRAHUB_IMAGE_NAME: "opsmill/infrahub"
INFRAHUB_IMAGE_VER: "local"
+ INFRAHUB_SERVER_PORT: 0
jobs:
migration-tests:
@@ -73,11 +74,10 @@ jobs:
run: echo INFRAHUB_IMAGE_VER=${{ matrix.source_version }} >> $GITHUB_ENV
- name: "Clear docker environment"
run: docker compose -p $INFRAHUB_BUILD_NAME down -v --remove-orphans --rmi local
-
- - name: Select infrahub port
- run: echo "INFRAHUB_SERVER_PORT=$(shuf -n 1 -i 10000-30000)" >> $GITHUB_ENV
- name: Set INFRAHUB_URL
- run: echo "INFRAHUB_URL=http://localhost:${INFRAHUB_SERVER_PORT}" >> $GITHUB_ENV
+ run: |
+ PORT=$(docker compose -p $INFRAHUB_BUILD_NAME port infrahub-server 8000 | cut -d: -f2)
+ echo "INFRAHUB_URL=http://localhost:${PORT}" >> $GITHUB_ENV
- name: "Store start time"
run: echo TEST_START_TIME=$(date +%s)000 >> $GITHUB_ENV
@@ -126,15 +126,15 @@ jobs:
- name: Display server logs
if: always()
- run: docker logs "${INFRAHUB_BUILD_NAME}-infrahub-server-1"
+ run: docker logs "${INFRAHUB_BUILD_NAME}-server-1"
- name: Display git 1 logs
if: always()
- run: docker logs "${INFRAHUB_BUILD_NAME}-infrahub-git-1"
+ run: docker logs "${INFRAHUB_BUILD_NAME}-task-worker-1"
- name: Display git 2 logs
if: always()
- run: docker logs "${INFRAHUB_BUILD_NAME}-infrahub-git-2"
+ run: docker logs "${INFRAHUB_BUILD_NAME}-task-worker-2"
- name: Display database logs
if: always()
diff --git a/.gitignore b/.gitignore
index 7f2630f698..0fc6779979 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ coverage.xml
*.env
script.py
**/*.local.*
+local/*
.vscode/settings.json
node_modules/*
development/docker-compose.override.yml
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 96359c6623..bb94c87dec 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -13,7 +13,7 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
- rev: v0.5.0
+ rev: v0.6.6
hooks:
# Run the linter.
- id: ruff
diff --git a/.vale/styles/Infrahub/sentence-case.yml b/.vale/styles/Infrahub/sentence-case.yml
index 30f2e81512..85f5923388 100644
--- a/.vale/styles/Infrahub/sentence-case.yml
+++ b/.vale/styles/Infrahub/sentence-case.yml
@@ -52,6 +52,9 @@ exceptions:
- Namespace
- NATS
- Node
+ - OAuth2
+ - OIDC
+ - Open ID Connect
- OpsMill
- Pydantic
- Python
@@ -59,6 +62,7 @@ exceptions:
- REST
- RFile
- SDK
+ - Single sign-on
- TLS
- Tony Stark
- TransformPython
diff --git a/.vale/styles/spelling-exceptions.txt b/.vale/styles/spelling-exceptions.txt
index c0fb18b4a6..7034fa9926 100644
--- a/.vale/styles/spelling-exceptions.txt
+++ b/.vale/styles/spelling-exceptions.txt
@@ -64,6 +64,7 @@ Jotai
json
JSONSchema
kbps
+Keycloak
Loopbacks
markdownlint
max_count
@@ -100,6 +101,7 @@ toml
Towncrier
uncheck
uniqueness_constraints
+userinfo
validator
upsert
Upserting
diff --git a/.yamllint.yml b/.yamllint.yml
index 50d26e1acb..0e9210947b 100644
--- a/.yamllint.yml
+++ b/.yamllint.yml
@@ -2,6 +2,7 @@
extends: default
ignore: |
+ /.git
/.venv
/examples
/repositories
diff --git a/backend/infrahub/api/__init__.py b/backend/infrahub/api/__init__.py
index 84ed4b1a8d..ab1e0e104d 100644
--- a/backend/infrahub/api/__init__.py
+++ b/backend/infrahub/api/__init__.py
@@ -14,6 +14,8 @@
file,
internal,
menu,
+ oauth2,
+ oidc,
query,
schema,
storage,
@@ -29,6 +31,8 @@
router.include_router(file.router)
router.include_router(internal.router)
router.include_router(menu.router)
+router.include_router(oauth2.router)
+router.include_router(oidc.router)
router.include_router(query.router)
router.include_router(schema.router)
router.include_router(storage.router)
diff --git a/backend/infrahub/api/dependencies.py b/backend/infrahub/api/dependencies.py
index ad756e64aa..cb58029c39 100644
--- a/backend/infrahub/api/dependencies.py
+++ b/backend/infrahub/api/dependencies.py
@@ -85,9 +85,8 @@ async def get_branch_params(
at: Optional[str] = Query(None, description="Time to use for the query, in absolute or relative format"),
) -> BranchParams:
branch = await registry.get_branch(db=db, branch=branch_name)
- at = Timestamp(at)
- return BranchParams(branch=branch, at=at)
+ return BranchParams(branch=branch, at=Timestamp(at))
async def get_branch_dep(
diff --git a/backend/infrahub/api/diff/diff.py b/backend/infrahub/api/diff/diff.py
index 3deaedb91d..e5ed7b4fed 100644
--- a/backend/infrahub/api/diff/diff.py
+++ b/backend/infrahub/api/diff/diff.py
@@ -24,7 +24,7 @@
DiffPayloadBuilder,
get_display_labels_per_kind,
)
-from infrahub.core.schema_manager import INTERNAL_SCHEMA_NODE_KINDS
+from infrahub.core.schema.constants import INTERNAL_SCHEMA_NODE_KINDS
from infrahub.database import InfrahubDatabase # noqa: TCH001
from .validation_models import DiffQueryValidated
@@ -195,7 +195,7 @@ async def get_diff_artifacts(
if not target:
continue
definition_id = node.elements["definition"].peer.new.id
- artifacts_in_main[(target.id, definition_id)] = node
+ artifacts_in_main[target.id, definition_id] = node
for node in payload[branch.name]:
if "storage_id" not in node.elements or "checksum" not in node.elements:
@@ -231,7 +231,7 @@ async def get_diff_artifacts(
and (target.id, node.elements["definition"].peer.new.id) in artifacts_in_main
):
diff_artifact.action = DiffAction.UPDATED
- node_in_main = artifacts_in_main[(target.id, node.elements["definition"].peer.new.id)]
+ node_in_main = artifacts_in_main[target.id, node.elements["definition"].peer.new.id]
diff_artifact.item_previous = BranchDiffArtifactStorage(
storage_id=node_in_main.elements["storage_id"].value.value.new,
checksum=node_in_main.elements["checksum"].value.value.new,
diff --git a/backend/infrahub/api/internal.py b/backend/infrahub/api/internal.py
index e6f72a1f13..2618ee4782 100644
--- a/backend/infrahub/api/internal.py
+++ b/backend/infrahub/api/internal.py
@@ -20,6 +20,7 @@ class ConfigAPI(BaseModel):
logging: LoggingSettings
analytics: AnalyticsSettings
experimental_features: ExperimentalFeaturesSettings
+ sso: config.SSOInfo
class InfoAPI(BaseModel):
@@ -34,6 +35,7 @@ async def get_config() -> ConfigAPI:
logging=config.SETTINGS.logging,
analytics=config.SETTINGS.analytics,
experimental_features=config.SETTINGS.experimental_features,
+ sso=config.SETTINGS.security.public_sso_config,
)
diff --git a/backend/infrahub/api/menu.py b/backend/infrahub/api/menu.py
index 4f16a06424..e622c61114 100644
--- a/backend/infrahub/api/menu.py
+++ b/backend/infrahub/api/menu.py
@@ -5,15 +5,21 @@
from fastapi import APIRouter, Depends
from pydantic import BaseModel, Field
-from infrahub.api.dependencies import get_branch_dep
+from infrahub.api.dependencies import get_branch_dep, get_current_user, get_db
from infrahub.core import registry
from infrahub.core.branch import Branch # noqa: TCH001
from infrahub.core.constants import InfrahubKind
+from infrahub.core.protocols import CoreMenuItem
from infrahub.core.schema import NodeSchema
from infrahub.log import get_logger
+from infrahub.menu.generator import generate_menu
+from infrahub.menu.models import Menu # noqa: TCH001
if TYPE_CHECKING:
+ from infrahub.auth import AccountSession
from infrahub.core.schema import MainSchemaTypes
+ from infrahub.database import InfrahubDatabase
+
log = get_logger()
router = APIRouter(prefix="/menu")
@@ -198,9 +204,9 @@ async def get_menu(branch: Branch = Depends(get_branch_dep)) -> list[InterfaceMe
title="Admin",
children=[
InterfaceMenu(
- title="Accounts",
- path=f"/objects/{InfrahubKind.GENERICACCOUNT}",
- icon=_extract_node_icon(full_schema[InfrahubKind.GENERICACCOUNT]),
+ title="Role Management",
+ path="/role-management",
+ icon=_extract_node_icon(full_schema[InfrahubKind.BASEPERMISSION]),
),
InterfaceMenu(
title="Credentials",
@@ -231,3 +237,17 @@ async def get_menu(branch: Branch = Depends(get_branch_dep)) -> list[InterfaceMe
menu_items.extend([groups, unified_storage, change_control, deployment, admin])
return menu_items
+
+
+@router.get("/new")
+async def get_new_menu(
+ db: InfrahubDatabase = Depends(get_db),
+ branch: Branch = Depends(get_branch_dep),
+ account_session: AccountSession = Depends(get_current_user),
+) -> Menu:
+ log.info("new_menu_request", branch=branch.name)
+
+ menu_items = await registry.manager.query(db=db, schema=CoreMenuItem, branch=branch, prefetch_relationships=True)
+ menu = await generate_menu(db=db, branch=branch, account=account_session, menu_items=menu_items)
+
+ return menu.to_rest()
diff --git a/backend/infrahub/api/oauth2.py b/backend/infrahub/api/oauth2.py
new file mode 100644
index 0000000000..a10cf58841
--- /dev/null
+++ b/backend/infrahub/api/oauth2.py
@@ -0,0 +1,125 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from urllib.parse import urljoin
+
+from authlib.integrations.httpx_client import AsyncOAuth2Client
+from fastapi import APIRouter, Depends, Request, Response
+from fastapi.responses import JSONResponse, RedirectResponse
+
+from infrahub import config, models
+from infrahub.api.dependencies import get_db
+from infrahub.auth import signin_sso_account
+from infrahub.exceptions import GatewayError, ProcessingError
+from infrahub.log import get_logger
+from infrahub.message_bus.types import KVTTL
+
+if TYPE_CHECKING:
+ import httpx
+
+ from infrahub.database import InfrahubDatabase
+ from infrahub.services import InfrahubServices
+
+log = get_logger()
+router = APIRouter(prefix="/oauth2")
+
+
+def _get_redirect_url(request: Request, provider_name: str) -> str:
+ """This function is mostly to support local development when the frontend runs on different ports compared to the API."""
+ base_url = config.SETTINGS.dev.frontend_url or str(request.base_url)
+ return urljoin(base_url, f"auth/oauth2/{provider_name}/callback")
+
+
+@router.get("/{provider_name:str}/authorize")
+async def authorize(request: Request, provider_name: str, final_url: str | None = None) -> Response:
+ provider = config.SETTINGS.security.get_oauth2_provider(provider=provider_name)
+ client = AsyncOAuth2Client(
+ client_id=provider.client_id,
+ client_secret=provider.client_secret,
+ scope=provider.scopes,
+ )
+
+ redirect_uri = _get_redirect_url(request=request, provider_name=provider_name)
+ final_url = final_url or config.SETTINGS.dev.frontend_url or str(request.base_url)
+
+ authorization_uri, state = client.create_authorization_url(
+ url=provider.authorization_url, redirect_uri=redirect_uri, scope=provider.scopes, final_url=final_url
+ )
+
+ service: InfrahubServices = request.app.state.service
+
+ await service.cache.set(
+ key=f"security:oauth2:provider:{provider_name}:state:{state}", value=final_url, expires=KVTTL.TWO_HOURS
+ )
+
+ if config.SETTINGS.dev.frontend_redirect_sso:
+ return JSONResponse(content={"url": authorization_uri})
+
+ return RedirectResponse(url=authorization_uri)
+
+
+@router.get("/{provider_name:str}/token")
+async def token(
+ request: Request,
+ response: Response,
+ provider_name: str,
+ state: str,
+ code: str,
+ db: InfrahubDatabase = Depends(get_db),
+) -> models.UserTokenWithUrl:
+ provider = config.SETTINGS.security.get_oauth2_provider(provider=provider_name)
+
+ service: InfrahubServices = request.app.state.service
+
+ cache_key = f"security:oauth2:provider:{provider_name}:state:{state}"
+ stored_final_url = await service.cache.get(key=cache_key)
+ await service.cache.delete(key=cache_key)
+
+ if not stored_final_url:
+ raise ProcessingError(message="Invalid 'state' parameter")
+
+ token_data = {
+ "code": code,
+ "client_id": provider.client_id,
+ "client_secret": provider.client_secret,
+ "redirect_uri": _get_redirect_url(request=request, provider_name=provider_name),
+ "grant_type": "authorization_code",
+ }
+
+ token_response = await service.http.post(provider.token_url, data=token_data)
+ _validate_response(response=token_response)
+ payload = token_response.json()
+
+ headers = {"Authorization": f"{payload.get('token_type')} {payload.get('access_token')}"}
+ userinfo_response = await service.http.post(provider.userinfo_url, headers=headers)
+ _validate_response(response=userinfo_response)
+ user_info = userinfo_response.json()
+ sso_groups = user_info.get("groups", [])
+ user_token = await signin_sso_account(db=db, account_name=user_info["name"], sso_groups=sso_groups)
+
+ response.set_cookie(
+ "access_token", user_token.access_token, httponly=True, max_age=config.SETTINGS.security.access_token_lifetime
+ )
+ response.set_cookie(
+ "refresh_token",
+ user_token.refresh_token,
+ httponly=True,
+ max_age=config.SETTINGS.security.refresh_token_lifetime,
+ )
+
+ return models.UserTokenWithUrl(
+ access_token=user_token.access_token, refresh_token=user_token.refresh_token, final_url=stored_final_url
+ )
+
+
+def _validate_response(response: httpx.Response) -> None:
+ if 200 <= response.status_code <= 299:
+ return
+
+ log.error(
+ "Invalid response from the OAuth provider",
+ url=response.url,
+ status_code=response.status_code,
+ body=response.json(),
+ )
+ raise GatewayError(message="Invalid response from Authentication provider")
diff --git a/backend/infrahub/api/oidc.py b/backend/infrahub/api/oidc.py
new file mode 100644
index 0000000000..ffc150e7e1
--- /dev/null
+++ b/backend/infrahub/api/oidc.py
@@ -0,0 +1,164 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from urllib.parse import urljoin
+
+from authlib.integrations.httpx_client import AsyncOAuth2Client
+from fastapi import APIRouter, Depends, Request, Response
+from fastapi.responses import JSONResponse, RedirectResponse
+from pydantic import BaseModel, HttpUrl
+
+from infrahub import config, models
+from infrahub.api.dependencies import get_db
+from infrahub.auth import signin_sso_account
+from infrahub.exceptions import GatewayError, ProcessingError
+from infrahub.log import get_logger
+from infrahub.message_bus.types import KVTTL
+
+if TYPE_CHECKING:
+ import httpx
+
+ from infrahub.database import InfrahubDatabase
+ from infrahub.services import InfrahubServices
+
+log = get_logger()
+router = APIRouter(prefix="/oidc")
+
+
+class OIDCDiscoveryConfig(BaseModel):
+ issuer: HttpUrl
+ authorization_endpoint: HttpUrl
+ token_endpoint: HttpUrl
+ userinfo_endpoint: HttpUrl
+ jwks_uri: HttpUrl
+ revocation_endpoint: HttpUrl | None = None
+ registration_endpoint: HttpUrl | None = None
+ introspection_endpoint: HttpUrl | None = None
+ end_session_endpoint: HttpUrl | None = None
+ frontchannel_logout_supported: bool | None = None
+ frontchannel_logout_session_supported: bool | None = None
+ grant_types_supported: list[str] | None = None
+ response_types_supported: list[str]
+ subject_types_supported: list[str]
+ id_token_signing_alg_values_supported: list[str]
+ scopes_supported: list[str] | None = None
+ token_endpoint_auth_methods_supported: list[str] | None = None
+ claims_supported: list[str] | None = None
+ acr_values_supported: list[str] | None = None
+ request_parameter_supported: bool | None = None
+ request_uri_parameter_supported: bool | None = None
+ require_request_uri_registration: bool | None = None
+ code_challenge_methods_supported: list[str] | None = None
+ tls_client_certificate_bound_access_tokens: bool | None = None
+ mtls_endpoint_aliases: dict[str, HttpUrl] | None = None
+
+
+def _get_redirect_url(request: Request, provider_name: str) -> str:
+ """This function is mostly to support local development when the frontend runs on different ports compared to the API."""
+ base_url = config.SETTINGS.dev.frontend_url or str(request.base_url)
+ return urljoin(base_url, f"auth/oidc/{provider_name}/callback")
+
+
+@router.get("/{provider_name:str}/authorize")
+async def authorize(request: Request, provider_name: str, final_url: str | None = None) -> Response:
+ provider = config.SETTINGS.security.get_oidc_provider(provider=provider_name)
+ service: InfrahubServices = request.app.state.service
+
+ response = await service.http.get(url=provider.discovery_url)
+ _validate_response(response=response)
+ oidc_config = OIDCDiscoveryConfig(**response.json())
+
+ client = AsyncOAuth2Client(
+ client_id=provider.client_id,
+ client_secret=provider.client_secret,
+ scope=provider.scopes,
+ )
+
+ redirect_uri = _get_redirect_url(request=request, provider_name=provider_name)
+ final_url = final_url or config.SETTINGS.dev.frontend_url or str(request.base_url)
+
+ authorization_uri, state = client.create_authorization_url(
+ url=str(oidc_config.authorization_endpoint), redirect_uri=redirect_uri, scope=provider.scopes
+ )
+
+ await service.cache.set(
+ key=f"security:oidc:provider:{provider_name}:state:{state}", value=final_url, expires=KVTTL.TWO_HOURS
+ )
+
+ if config.SETTINGS.dev.frontend_redirect_sso:
+ return JSONResponse(content={"url": authorization_uri})
+
+ return RedirectResponse(url=authorization_uri)
+
+
+@router.get("/{provider_name:str}/token")
+async def token(
+ request: Request,
+ response: Response,
+ provider_name: str,
+ state: str,
+ code: str,
+ db: InfrahubDatabase = Depends(get_db),
+) -> models.UserTokenWithUrl:
+ provider = config.SETTINGS.security.get_oidc_provider(provider=provider_name)
+
+ service: InfrahubServices = request.app.state.service
+
+ cache_key = f"security:oidc:provider:{provider_name}:state:{state}"
+ stored_final_url = await service.cache.get(key=cache_key)
+ await service.cache.delete(key=cache_key)
+
+ if not stored_final_url:
+ raise ProcessingError(message="Invalid 'state' parameter")
+
+ token_data = {
+ "code": code,
+ "client_id": provider.client_id,
+ "client_secret": provider.client_secret,
+ "redirect_uri": _get_redirect_url(request=request, provider_name=provider_name),
+ "grant_type": "authorization_code",
+ }
+
+ discovery_response = await service.http.get(url=provider.discovery_url)
+ _validate_response(response=discovery_response)
+
+ oidc_config = OIDCDiscoveryConfig(**discovery_response.json())
+
+ token_response = await service.http.post(str(oidc_config.token_endpoint), data=token_data)
+ _validate_response(response=token_response)
+ payload = token_response.json()
+
+ headers = {"Authorization": f"{payload.get('token_type')} {payload.get('access_token')}"}
+ userinfo_response = await service.http.post(str(oidc_config.userinfo_endpoint), headers=headers)
+ _validate_response(response=userinfo_response)
+ user_info = userinfo_response.json()
+
+ sso_groups = user_info.get("groups", [])
+ user_token = await signin_sso_account(db=db, account_name=user_info["name"], sso_groups=sso_groups)
+
+ response.set_cookie(
+ "access_token", user_token.access_token, httponly=True, max_age=config.SETTINGS.security.access_token_lifetime
+ )
+ response.set_cookie(
+ "refresh_token",
+ user_token.refresh_token,
+ httponly=True,
+ max_age=config.SETTINGS.security.refresh_token_lifetime,
+ )
+
+ return models.UserTokenWithUrl(
+ access_token=user_token.access_token, refresh_token=user_token.refresh_token, final_url=stored_final_url
+ )
+
+
+def _validate_response(response: httpx.Response) -> None:
+ if 200 <= response.status_code <= 299:
+ return
+
+ log.error(
+ "Invalid response from the OIDC provider",
+ url=response.url,
+ status_code=response.status_code,
+ body=response.json(),
+ )
+ raise GatewayError(message="Invalid response from Authentication provider")
diff --git a/backend/infrahub/api/query.py b/backend/infrahub/api/query.py
index f96810b758..c7780c9f8a 100644
--- a/backend/infrahub/api/query.py
+++ b/backend/infrahub/api/query.py
@@ -10,8 +10,9 @@
from infrahub.core import registry
from infrahub.core.constants import InfrahubKind
from infrahub.database import InfrahubDatabase # noqa: TCH001
-from infrahub.graphql import prepare_graphql_params
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.api.dependencies import build_graphql_query_permission_checker
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.graphql.metrics import (
GRAPHQL_DURATION_METRICS,
GRAPHQL_QUERY_DEPTH_METRICS,
@@ -26,8 +27,11 @@
from infrahub.message_bus import messages
if TYPE_CHECKING:
+ from infrahub.auth import AccountSession
+ from infrahub.graphql.auth.query_permission_checker.checker import GraphQLQueryPermissionChecker
from infrahub.services import InfrahubServices
+
log = get_logger()
router = APIRouter(prefix="/query")
@@ -44,17 +48,28 @@ async def execute_query(
params: dict[str, str],
update_group: bool,
subscribers: list[str],
+ permission_checker: GraphQLQueryPermissionChecker,
+ account_session: AccountSession,
) -> dict[str, Any]:
gql_query = await registry.manager.get_one_by_id_or_default_filter(
db=db, id=query_id, kind=InfrahubKind.GRAPHQLQUERY, branch=branch_params.branch, at=branch_params.at
)
- gql_params = prepare_graphql_params(db=db, branch=branch_params.branch, at=branch_params.at)
+ gql_params = prepare_graphql_params(
+ db=db, branch=branch_params.branch, at=branch_params.at, account_session=account_session
+ )
analyzed_query = InfrahubGraphQLQueryAnalyzer(
query=gql_query.query.value, # type: ignore[attr-defined]
schema=gql_params.schema,
branch=branch_params.branch,
)
+ await permission_checker.check(
+ db=db,
+ account_session=account_session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=branch_params.branch,
+ )
labels = {
"type": "mutation" if analyzed_query.contains_mutation else "query",
@@ -120,7 +135,8 @@ async def graphql_query_post(
),
db: InfrahubDatabase = Depends(get_db),
branch_params: BranchParams = Depends(get_branch_params),
- _: str = Depends(get_current_user),
+ account_session: AccountSession = Depends(get_current_user),
+ permission_checker: GraphQLQueryPermissionChecker = Depends(build_graphql_query_permission_checker),
) -> dict:
return await execute_query(
db=db,
@@ -130,6 +146,8 @@ async def graphql_query_post(
params=payload.variables,
update_group=update_group,
subscribers=subscribers,
+ permission_checker=permission_checker,
+ account_session=account_session,
)
@@ -146,7 +164,8 @@ async def graphql_query_get(
),
db: InfrahubDatabase = Depends(get_db),
branch_params: BranchParams = Depends(get_branch_params),
- _: str = Depends(get_current_user),
+ account_session: AccountSession = Depends(get_current_user),
+ permission_checker: GraphQLQueryPermissionChecker = Depends(build_graphql_query_permission_checker),
) -> dict:
params = {
key: value
@@ -162,4 +181,6 @@ async def graphql_query_get(
params=params,
update_group=update_group,
subscribers=subscribers,
+ permission_checker=permission_checker,
+ account_session=account_session,
)
diff --git a/backend/infrahub/api/schema.py b/backend/infrahub/api/schema.py
index 5c8eafb7b3..e852eb0acd 100644
--- a/backend/infrahub/api/schema.py
+++ b/backend/infrahub/api/schema.py
@@ -17,11 +17,15 @@
from infrahub.api.exceptions import SchemaNotValidError
from infrahub.core import registry
from infrahub.core.branch import Branch # noqa: TCH001
-from infrahub.core.migrations.schema.runner import schema_migrations_runner
-from infrahub.core.models import SchemaBranchHash, SchemaDiff # noqa: TCH001
+from infrahub.core.migrations.schema.models import SchemaApplyMigrationData
+from infrahub.core.models import ( # noqa: TCH001
+ SchemaBranchHash,
+ SchemaDiff,
+ SchemaUpdateValidationResult,
+)
from infrahub.core.schema import GenericSchema, MainSchemaTypes, NodeSchema, ProfileSchema, SchemaRoot
-from infrahub.core.schema_manager import SchemaBranch, SchemaNamespace, SchemaUpdateValidationResult # noqa: TCH001
-from infrahub.core.validators.checker import schema_validators_checker
+from infrahub.core.schema.constants import SchemaNamespace # noqa: TCH001
+from infrahub.core.validators.models.validate_migration import SchemaValidateMigrationData
from infrahub.database import InfrahubDatabase # noqa: TCH001
from infrahub.exceptions import MigrationError
from infrahub.log import get_logger
@@ -29,10 +33,12 @@
from infrahub.services import services
from infrahub.types import ATTRIBUTE_PYTHON_TYPES
from infrahub.worker import WORKER_IDENTITY
+from infrahub.workflows.catalogue import SCHEMA_APPLY_MIGRATION, SCHEMA_VALIDATE_MIGRATION
if TYPE_CHECKING:
from typing_extensions import Self
+ from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.services import InfrahubServices
@@ -258,11 +264,16 @@ async def load_schema(
# ----------------------------------------------------------
# Validate if the new schema is valid with the content of the database
# ----------------------------------------------------------
- error_messages, _ = await schema_validators_checker(
- branch=branch, schema=candidate_schema, constraints=result.constraints, service=service
+ validate_migration_data = SchemaValidateMigrationData(
+ branch=branch,
+ schema_branch=candidate_schema,
+ constraints=result.constraints,
+ )
+ error_messages = await service.workflow.execute( # type: ignore[var-annotated]
+ workflow=SCHEMA_VALIDATE_MIGRATION, message=validate_migration_data
)
- if error_messages:
- raise SchemaNotValidError(message=",\n".join(error_messages))
+ if error_messages: # type: ignore[has-type]
+ raise SchemaNotValidError(message=",\n".join(error_messages)) # type: ignore[has-type]
# ----------------------------------------------------------
# Update the schema
@@ -293,15 +304,18 @@ async def load_schema(
# ----------------------------------------------------------
# Run the migrations
# ----------------------------------------------------------
- error_messages = await schema_migrations_runner(
+ apply_migration_data = SchemaApplyMigrationData(
branch=branch,
new_schema=candidate_schema,
previous_schema=origin_schema,
migrations=result.migrations,
- service=service,
)
- if error_messages:
- raise MigrationError(message=",\n".join(error_messages))
+ migration_error_msgs = await service.workflow.execute( # type: ignore[var-annotated]
+ workflow=SCHEMA_APPLY_MIGRATION, message=apply_migration_data
+ )
+
+ if migration_error_msgs:
+ raise MigrationError(message=",\n".join(migration_error_msgs))
if config.SETTINGS.broker.enable:
message = messages.EventSchemaUpdate(
@@ -339,8 +353,13 @@ async def check_schema(
# ----------------------------------------------------------
# Validate if the new schema is valid with the content of the database
# ----------------------------------------------------------
- error_messages, _ = await schema_validators_checker(
- branch=branch, schema=candidate_schema, constraints=result.constraints, service=service
+ validate_migration_data = SchemaValidateMigrationData(
+ branch=branch,
+ schema_branch=candidate_schema,
+ constraints=result.constraints,
+ )
+ error_messages = await service.workflow.execute( # type: ignore[var-annotated]
+ workflow=SCHEMA_VALIDATE_MIGRATION, message=validate_migration_data
)
if error_messages:
raise SchemaNotValidError(message=",\n".join(error_messages))
diff --git a/backend/infrahub/api/transformation.py b/backend/infrahub/api/transformation.py
index 153386df32..d4b620b420 100644
--- a/backend/infrahub/api/transformation.py
+++ b/backend/infrahub/api/transformation.py
@@ -21,14 +21,14 @@
)
from infrahub.database import InfrahubDatabase # noqa: TCH001
from infrahub.exceptions import TransformError
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.graphql.utils import extract_data
from infrahub.message_bus.messages import (
- TransformJinjaTemplate,
- TransformJinjaTemplateResponse,
TransformPythonData,
TransformPythonDataResponse,
)
+from infrahub.message_bus.messages.transform_jinja_template import TransformJinjaTemplateData
+from infrahub.workflows.catalogue import TRANSFORM_JINJA2_RENDER
if TYPE_CHECKING:
from infrahub.services import InfrahubServices
@@ -134,9 +134,7 @@ async def transform_jinja2(
data = extract_data(query_name=query.name.value, result=result)
- service: InfrahubServices = request.app.state.service
-
- message = TransformJinjaTemplate(
+ message = TransformJinjaTemplateData(
repository_id=repository.id,
repository_name=repository.name.value,
repository_kind=repository.get_kind(),
@@ -146,5 +144,8 @@ async def transform_jinja2(
data=data,
)
- response = await service.message_bus.rpc(message=message, response_class=TransformJinjaTemplateResponse)
- return PlainTextResponse(content=response.data.rendered_template)
+ service: InfrahubServices = request.app.state.service
+
+ response: str = await service.workflow.execute(workflow=TRANSFORM_JINJA2_RENDER, message=message) # type: ignore[arg-type]
+
+ return PlainTextResponse(content=response)
diff --git a/backend/infrahub/auth.py b/backend/infrahub/auth.py
index 861f98767d..cda103eb07 100644
--- a/backend/infrahub/auth.py
+++ b/backend/infrahub/auth.py
@@ -14,6 +14,7 @@
from infrahub.core.constants import AccountStatus, InfrahubKind
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
+from infrahub.core.protocols import CoreAccount, CoreAccountGroup
from infrahub.core.registry import registry
from infrahub.exceptions import AuthorizationError, NodeNotFoundError
@@ -123,6 +124,35 @@ async def create_fresh_access_token(
return models.AccessTokenResponse(access_token=access_token)
+async def signin_sso_account(db: InfrahubDatabase, account_name: str, sso_groups: list[str]) -> models.UserToken:
+ account = await NodeManager.get_one_by_default_filter(db=db, id=account_name, kind=InfrahubKind.ACCOUNT)
+
+ if not account:
+ account = await Node.init(db=db, schema=InfrahubKind.ACCOUNT)
+ await account.new(db=db, name=account_name, account_type="User", role="admin", password=str(uuid.uuid4()))
+ await account.save(db=db)
+
+ if sso_groups:
+ infrahub_groups = await NodeManager.query(
+ db=db,
+ schema=CoreAccountGroup,
+ filters={"name__values": sso_groups},
+ prefetch_relationships=True,
+ )
+ for group in infrahub_groups:
+ members = await group.members.get_peers(db=db, branch_agnostic=True, peer_type=CoreAccount)
+ if account.id not in members:
+ await group.members.add(db=db, data=account)
+ await group.members.save(db=db)
+
+ now = datetime.now(tz=timezone.utc)
+ refresh_expires = now + timedelta(seconds=config.SETTINGS.security.refresh_token_lifetime)
+ session_id = await create_db_refresh_token(db=db, account_id=account.id, expiration=refresh_expires)
+ access_token = generate_access_token(account_id=account.id, role=account.role.value.value, session_id=session_id)
+ refresh_token = generate_refresh_token(account_id=account.id, session_id=session_id, expiration=refresh_expires)
+ return models.UserToken(access_token=access_token, refresh_token=refresh_token)
+
+
def generate_access_token(account_id: str, role: str, session_id: uuid.UUID) -> str:
now = datetime.now(tz=timezone.utc)
diff --git a/backend/infrahub/cli/__init__.py b/backend/infrahub/cli/__init__.py
index f6d042be32..5320e89803 100644
--- a/backend/infrahub/cli/__init__.py
+++ b/backend/infrahub/cli/__init__.py
@@ -8,6 +8,7 @@
from infrahub.cli.events import app as events_app
from infrahub.cli.git_agent import app as git_app
from infrahub.cli.server import app as server_app
+from infrahub.cli.tasks import app as tasks_app
from infrahub.core.initialization import initialization
from infrahub.database import InfrahubDatabase, get_db
@@ -26,6 +27,7 @@ def common(ctx: typer.Context) -> None:
app.add_typer(git_app, name="git-agent")
app.add_typer(db_app, name="db")
app.add_typer(events_app, name="events", help="Interact with the events system.")
+app.add_typer(tasks_app, name="tasks", hidden=True)
async def _init_shell(config_file: str) -> None:
diff --git a/backend/infrahub/cli/db.py b/backend/infrahub/cli/db.py
index 1fbaebc2a1..80271a4e07 100644
--- a/backend/infrahub/cli/db.py
+++ b/backend/infrahub/cli/db.py
@@ -1,10 +1,12 @@
import importlib
import logging
+import os
from enum import Enum
from typing import TYPE_CHECKING, Optional
import typer
from infrahub_sdk.async_typer import AsyncTyper
+from prefect.testing.utilities import prefect_test_harness
from rich import print as rprint
from rich.console import Console
from rich.logging import RichHandler
@@ -18,16 +20,18 @@
from infrahub.core.graph.schema import GRAPH_SCHEMA
from infrahub.core.initialization import first_time_initialization, get_root_node, initialization, initialize_registry
from infrahub.core.migrations.graph import get_graph_migrations
-from infrahub.core.migrations.schema.runner import schema_migrations_runner
+from infrahub.core.migrations.schema.models import SchemaApplyMigrationData
from infrahub.core.schema import SchemaRoot, core_models, internal_schema
from infrahub.core.schema.definitions.deprecated import deprecated_models
-from infrahub.core.schema_manager import SchemaManager
+from infrahub.core.schema.manager import SchemaManager
from infrahub.core.utils import delete_all_nodes
-from infrahub.core.validators.checker import schema_validators_checker
+from infrahub.core.validators.models.validate_migration import SchemaValidateMigrationData
from infrahub.database import DatabaseType
from infrahub.log import get_logger
from infrahub.services import InfrahubServices
from infrahub.services.adapters.message_bus.local import BusSimulator
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
+from infrahub.workflows.catalogue import SCHEMA_APPLY_MIGRATION, SCHEMA_VALIDATE_MIGRATION
if TYPE_CHECKING:
from infrahub.cli.context import CliContext
@@ -177,6 +181,9 @@ async def update_core_schema( # pylint: disable=too-many-statements
"""Check the current format of the internal graph and apply the necessary migrations"""
logging.getLogger("infrahub").setLevel(logging.WARNING)
logging.getLogger("neo4j").setLevel(logging.ERROR)
+ logging.getLogger("prefect").setLevel(logging.ERROR)
+ os.environ["PREFECT_SERVER_ANALYTICS_ENABLED"] = "false"
+
config.load_and_exit(config_file_name=config_file)
context: CliContext = ctx.obj
@@ -185,98 +192,109 @@ async def update_core_schema( # pylint: disable=too-many-statements
error_badge = "[bold red]ERROR[/bold red]"
async with dbdriver.start_session() as db:
- # ----------------------------------------------------------
- # Initialize Schema and Registry
- # ----------------------------------------------------------
- service = InfrahubServices(database=db, message_bus=BusSimulator(database=db))
- await initialize_registry(db=db)
-
- default_branch = registry.get_branch_from_registry(branch=registry.default_branch)
-
- registry.schema = SchemaManager()
- schema = SchemaRoot(**internal_schema)
- registry.schema.register_schema(schema=schema)
-
- # ----------------------------------------------------------
- # Load Current Schema from the database
- # ----------------------------------------------------------
- schema_default_branch = await registry.schema.load_schema_from_db(db=db, branch=default_branch)
- registry.schema.set_schema_branch(name=default_branch.name, schema=schema_default_branch)
- branch_schema = registry.schema.get_schema_branch(name=registry.default_branch)
-
- candidate_schema = branch_schema.duplicate()
- candidate_schema.load_schema(schema=SchemaRoot(**internal_schema))
- candidate_schema.load_schema(schema=SchemaRoot(**core_models))
- candidate_schema.load_schema(schema=SchemaRoot(**deprecated_models))
- candidate_schema.process()
-
- result = branch_schema.validate_update(other=candidate_schema, enforce_update_support=False)
- if result.errors:
- rprint(f"{error_badge} | Unable to update the schema, due to failed validations")
- for error in result.errors:
- rprint(error.to_string())
- raise typer.Exit(1)
-
- if not result.diff.all:
- rprint("Core Schema Up to date, nothing to update")
- raise typer.Exit(0)
-
- rprint("Core Schema has diff, will need to be updated")
- if debug:
- result.diff.print()
-
- # ----------------------------------------------------------
- # Validate if the new schema is valid with the content of the database
- # ----------------------------------------------------------
- error_messages, _ = await schema_validators_checker(
- branch=default_branch, schema=candidate_schema, constraints=result.constraints, service=service
- )
- if error_messages:
- rprint(f"{error_badge} | Unable to update the schema, due to failed validations")
- for message in error_messages:
- rprint(message)
- raise typer.Exit(1)
-
- # ----------------------------------------------------------
- # Update the schema
- # ----------------------------------------------------------
- origin_schema = branch_schema.duplicate()
-
- # Update the internal schema
- schema_default_branch.load_schema(schema=SchemaRoot(**internal_schema))
- schema_default_branch.process()
- registry.schema.set_schema_branch(name=default_branch.name, schema=schema_default_branch)
-
- async with db.start_transaction() as dbt:
- await registry.schema.update_schema_branch(
- schema=candidate_schema,
- db=dbt,
- branch=default_branch.name,
- diff=result.diff,
- limit=result.diff.all,
- update_db=True,
+ with prefect_test_harness():
+ # ----------------------------------------------------------
+ # Initialize Schema and Registry
+ # ----------------------------------------------------------
+ service = InfrahubServices(
+ database=db, message_bus=BusSimulator(database=db), workflow=WorkflowLocalExecution()
)
- default_branch.update_schema_hash()
- rprint("The Core Schema has been updated")
+ await initialize_registry(db=db)
+
+ default_branch = registry.get_branch_from_registry(branch=registry.default_branch)
+
+ registry.schema = SchemaManager()
+ schema = SchemaRoot(**internal_schema)
+ registry.schema.register_schema(schema=schema)
+
+ # ----------------------------------------------------------
+ # Load Current Schema from the database
+ # ----------------------------------------------------------
+ schema_default_branch = await registry.schema.load_schema_from_db(db=db, branch=default_branch)
+ registry.schema.set_schema_branch(name=default_branch.name, schema=schema_default_branch)
+ branch_schema = registry.schema.get_schema_branch(name=registry.default_branch)
+
+ candidate_schema = branch_schema.duplicate()
+ candidate_schema.load_schema(schema=SchemaRoot(**internal_schema))
+ candidate_schema.load_schema(schema=SchemaRoot(**core_models))
+ candidate_schema.load_schema(schema=SchemaRoot(**deprecated_models))
+ candidate_schema.process()
+
+ result = branch_schema.validate_update(other=candidate_schema, enforce_update_support=False)
+ if result.errors:
+ rprint(f"{error_badge} | Unable to update the schema, due to failed validations")
+ for error in result.errors:
+ rprint(error.to_string())
+ raise typer.Exit(1)
+
+ if not result.diff.all:
+ rprint("Core Schema Up to date, nothing to update")
+ raise typer.Exit(0)
+
+ rprint("Core Schema has diff, will need to be updated")
if debug:
- rprint(f"New schema hash: {default_branch.active_schema_hash.main}")
- await default_branch.save(db=dbt)
-
- # ----------------------------------------------------------
- # Run the migrations
- # ----------------------------------------------------------
- error_messages = await schema_migrations_runner(
- branch=default_branch,
- new_schema=candidate_schema,
- previous_schema=origin_schema,
- migrations=result.migrations,
- service=service,
- )
- if error_messages:
- rprint(f"{error_badge} | Some error(s) happened while running the schema migrations")
- for message in error_messages:
- rprint(message)
- raise typer.Exit(1)
+ result.diff.print()
+
+ # ----------------------------------------------------------
+ # Validate if the new schema is valid with the content of the database
+ # ----------------------------------------------------------
+ validate_migration_data = SchemaValidateMigrationData(
+ branch=default_branch,
+ schema_branch=candidate_schema,
+ constraints=result.constraints,
+ )
+ error_messages = await service.workflow.execute( # type: ignore[var-annotated]
+ workflow=SCHEMA_VALIDATE_MIGRATION, message=validate_migration_data
+ )
+ if error_messages:
+ rprint(f"{error_badge} | Unable to update the schema, due to failed validations")
+ for message in error_messages:
+ rprint(message)
+ raise typer.Exit(1)
+
+ # ----------------------------------------------------------
+ # Update the schema
+ # ----------------------------------------------------------
+ origin_schema = branch_schema.duplicate()
+
+ # Update the internal schema
+ schema_default_branch.load_schema(schema=SchemaRoot(**internal_schema))
+ schema_default_branch.process()
+ registry.schema.set_schema_branch(name=default_branch.name, schema=schema_default_branch)
+
+ async with db.start_transaction() as dbt:
+ await registry.schema.update_schema_branch(
+ schema=candidate_schema,
+ db=dbt,
+ branch=default_branch.name,
+ diff=result.diff,
+ limit=result.diff.all,
+ update_db=True,
+ )
+ default_branch.update_schema_hash()
+ rprint("The Core Schema has been updated")
+ if debug:
+ rprint(f"New schema hash: {default_branch.active_schema_hash.main}")
+ await default_branch.save(db=dbt)
+
+ # ----------------------------------------------------------
+ # Run the migrations
+ # ----------------------------------------------------------
+ apply_migration_data = SchemaApplyMigrationData(
+ branch=default_branch,
+ new_schema=candidate_schema,
+ previous_schema=origin_schema,
+ migrations=result.migrations,
+ )
+ migration_error_msgs = await service.workflow.execute( # type: ignore[var-annotated]
+ workflow=SCHEMA_APPLY_MIGRATION, message=apply_migration_data
+ )
+
+ if migration_error_msgs:
+ rprint(f"{error_badge} | Some error(s) happened while running the schema migrations")
+ for message in migration_error_msgs:
+ rprint(message)
+ raise typer.Exit(1)
@app.command()
diff --git a/backend/infrahub/cli/git_agent.py b/backend/infrahub/cli/git_agent.py
index ef163db558..3f0e20d319 100644
--- a/backend/infrahub/cli/git_agent.py
+++ b/backend/infrahub/cli/git_agent.py
@@ -23,6 +23,8 @@
from infrahub.services.adapters.cache.redis import RedisCache
from infrahub.services.adapters.message_bus.nats import NATSMessageBus
from infrahub.services.adapters.message_bus.rabbitmq import RabbitMQMessageBus
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
+from infrahub.services.adapters.workflow.worker import WorkflowWorkerExecution
from infrahub.trace import configure_trace
if TYPE_CHECKING:
@@ -69,6 +71,7 @@ async def start(
logging.getLogger("aio_pika").setLevel(logging.ERROR)
logging.getLogger("aiormq").setLevel(logging.ERROR)
logging.getLogger("git").setLevel(logging.ERROR)
+ logging.getLogger("aiosqlite").setLevel(logging.ERROR)
log.debug(f"Config file : {config_file}")
# Prevent git from interactively prompting the user for passwords if the credentials provided
@@ -110,6 +113,12 @@ async def start(
database = await context.get_db(retry=1)
+ workflow = config.OVERRIDE.workflow or (
+ WorkflowWorkerExecution()
+ if config.SETTINGS.workflow.driver == config.WorkflowDriver.WORKER
+ else WorkflowLocalExecution()
+ )
+
message_bus = config.OVERRIDE.message_bus or (
NATSMessageBus() if config.SETTINGS.broker.driver == config.BrokerDriver.NATS else RabbitMQMessageBus()
)
@@ -121,6 +130,7 @@ async def start(
cache=cache,
client=client,
database=database,
+ workflow=workflow,
message_bus=message_bus,
component_type=ComponentType.GIT_AGENT,
)
diff --git a/backend/infrahub/cli/tasks.py b/backend/infrahub/cli/tasks.py
new file mode 100644
index 0000000000..ffcff0bae4
--- /dev/null
+++ b/backend/infrahub/cli/tasks.py
@@ -0,0 +1,50 @@
+import logging
+
+import typer
+from infrahub_sdk.async_typer import AsyncTyper
+from prefect.client.orchestration import get_client
+
+from infrahub import config
+from infrahub.services.adapters.workflow.worker import WorkflowWorkerExecution
+from infrahub.tasks.dummy import DUMMY_FLOW, DummyInput
+from infrahub.workflows.initialization import setup_task_manager
+from infrahub.workflows.models import WorkerPoolDefinition
+
+app = AsyncTyper()
+
+# pylint: disable=unused-argument
+
+
+@app.command()
+async def init(
+ ctx: typer.Context,
+ debug: bool = typer.Option(False, help="Enable advanced logging and troubleshooting"),
+ config_file: str = typer.Argument("infrahub.toml", envvar="INFRAHUB_CONFIG"),
+) -> None:
+ """Initialize the task manager"""
+ logging.getLogger("prefect").setLevel(logging.ERROR)
+
+ config.load_and_exit(config_file_name=config_file)
+
+ await setup_task_manager()
+
+
+@app.command()
+async def execute(
+ ctx: typer.Context,
+ debug: bool = typer.Option(False, help="Enable advanced logging and troubleshooting"),
+ config_file: str = typer.Argument("infrahub.toml", envvar="INFRAHUB_CONFIG"),
+) -> None:
+ """Check the current format of the internal graph and apply the necessary migrations"""
+ logging.getLogger("infrahub").setLevel(logging.WARNING)
+ logging.getLogger("neo4j").setLevel(logging.ERROR)
+ logging.getLogger("prefect").setLevel(logging.ERROR)
+
+ config.load_and_exit(config_file_name=config_file)
+
+ async with get_client(sync_client=False) as client:
+ worker = WorkflowWorkerExecution()
+ await DUMMY_FLOW.save(client=client, work_pool=WorkerPoolDefinition(name="testing", worker_type="process"))
+
+ result = await worker.execute(workflow=DUMMY_FLOW, data=DummyInput(firstname="John", lastname="Doe")) # type: ignore[var-annotated]
+ print(result)
diff --git a/backend/infrahub/config.py b/backend/infrahub/config.py
index e5d21bb3f1..64b67802ef 100644
--- a/backend/infrahub/config.py
+++ b/backend/infrahub/config.py
@@ -2,6 +2,7 @@
import os
import os.path
+import ssl
import sys
from dataclasses import dataclass
from enum import Enum
@@ -10,16 +11,17 @@
import toml
from infrahub_sdk import generate_uuid
-from pydantic import AliasChoices, Field, ValidationError, model_validator
+from pydantic import AliasChoices, BaseModel, Field, PrivateAttr, ValidationError, computed_field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing_extensions import Self
from infrahub.database.constants import DatabaseType
-from infrahub.exceptions import InitializationError
+from infrahub.exceptions import InitializationError, ProcessingError
if TYPE_CHECKING:
from infrahub.services.adapters.cache import InfrahubCache
from infrahub.services.adapters.message_bus import InfrahubMessageBus
+ from infrahub.services.adapters.workflow import InfrahubWorkflow
VALID_DATABASE_NAME_REGEX = r"^[a-z][a-z0-9\.]+$"
@@ -34,6 +36,46 @@ def default_cors_allow_headers() -> list[str]:
return ["accept", "authorization", "content-type", "user-agent", "x-csrftoken", "x-requested-with"]
+class SSOProtocol(str, Enum):
+ OAUTH2 = "oauth2"
+ OIDC = "oidc"
+
+
+class Oauth2Provider(str, Enum):
+ GOOGLE = "google"
+ PROVIDER1 = "provider1"
+ PROVIDER2 = "provider2"
+
+
+class OIDCProvider(str, Enum):
+ GOOGLE = "google"
+ PROVIDER1 = "provider1"
+ PROVIDER2 = "provider2"
+
+
+class SSOInfo(BaseModel):
+ providers: list[SSOProviderInfo] = Field(default_factory=list)
+
+ @computed_field
+ def enabled(self) -> bool:
+ return bool(self.providers)
+
+
+class SSOProviderInfo(BaseModel):
+ name: str
+ display_label: str
+ icon: str
+ protocol: SSOProtocol
+
+ @computed_field
+ def authorize_path(self) -> str:
+ return f"/api/{self.protocol.value}/{self.name}/authorize"
+
+ @computed_field
+ def token_path(self) -> str:
+ return f"/api/{self.protocol.value}/{self.name}/token"
+
+
class StorageDriver(str, Enum):
FileSystemStorage = "local"
InfrahubS3ObjectStorage = "s3"
@@ -62,6 +104,11 @@ class CacheDriver(str, Enum):
NATS = "nats"
+class WorkflowDriver(str, Enum):
+ LOCAL = "local"
+ WORKER = "worker"
+
+
class MainSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_")
docs_index_path: str = Field(
@@ -77,6 +124,10 @@ class MainSettings(BaseSettings):
telemetry_interval: int = Field(
default=3600 * 24, ge=60, description="Time (in seconds) between telemetry usage push"
)
+ permission_backends: list[str] = Field(
+ default=["infrahub.permissions.LocalPermissionBackend"],
+ description="List of modules to handle permissions, they will be run in the given order",
+ )
class FileSystemStorageSettings(BaseSettings):
@@ -165,6 +216,21 @@ def database_name(self) -> str:
return self.database or self.db_type.value
+class DevelopmentSettings(BaseSettings):
+ """The development settings are only relevant for local development"""
+
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_DEV_")
+
+ frontend_url: Optional[str] = Field(
+ default=None,
+ description="Define the URL of the frontend, useful for OAuth2 development when the frontend and backend use different ports.",
+ )
+ frontend_redirect_sso: bool = Field(
+ default=False,
+ description="Indicates of the frontend should be responsible for the SSO redirection",
+ )
+
+
class BrokerSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_BROKER_")
enable: bool = True
@@ -175,6 +241,7 @@ class BrokerSettings(BaseSettings):
password: str = "infrahub"
address: str = "localhost"
port: Optional[int] = Field(default=None, ge=1, le=65535, description="Specified if running on a non default port.")
+ rabbitmq_http_port: Optional[int] = Field(default=None, ge=1, le=65535)
namespace: str = "infrahub"
maximum_message_retries: int = Field(
default=10, description="The maximum number of retries that are attempted for failed messages"
@@ -202,8 +269,8 @@ class CacheSettings(BaseSettings):
)
database: int = Field(default=0, ge=0, le=15, description="Id of the database to use")
driver: CacheDriver = CacheDriver.Redis
- username: str = "infrahub"
- password: str = "infrahub"
+ username: str = ""
+ password: str = ""
tls_enabled: bool = Field(default=False, description="Indicates if TLS is enabled for the connection")
tls_insecure: bool = Field(default=False, description="Indicates if TLS certificates are verified")
tls_ca_file: Optional[str] = Field(default=None, description="File path to CA cert or bundle in PEM format")
@@ -216,6 +283,27 @@ def service_port(self) -> int:
return self.port or default_ports
+class WorkflowSettings(BaseSettings):
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_WORKFLOW_")
+ enable: bool = True
+ address: str = "localhost"
+ port: Optional[int] = Field(default=None, ge=1, le=65535, description="Specified if running on a non default port.")
+ tls_enabled: bool = Field(default=False, description="Indicates if TLS is enabled for the connection")
+ driver: WorkflowDriver = WorkflowDriver.WORKER
+ worker_polling_interval: int = Field(
+ default=2, ge=1, le=30, description="Specify how often the worker should poll the server for tasks (sec)"
+ )
+
+ @property
+ def api_endpoint(self) -> str:
+ url = "https://" if self.tls_enabled else "http://"
+ url += self.address
+ if self.port:
+ url += f":{self.port}"
+ url += "/api"
+ return url
+
+
class ApiSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_API_")
cors_allow_origins: list[str] = Field(
@@ -242,6 +330,58 @@ class GitSettings(BaseSettings):
)
+class HTTPSettings(BaseSettings):
+ """The HTTP settings control how Infrahub interacts with external HTTP servers
+
+ This can be things like webhooks and OAuth2 providers"""
+
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_HTTP_")
+ timeout: int = Field(default=10, description="Default connection timeout in seconds")
+ tls_insecure: bool = Field(
+ default=False,
+ description="Indicates if Infrahub will validate server certificates or if the validation is ignored.",
+ )
+ tls_ca_bundle: str | None = Field(
+ default=None,
+ description="Custom CA bundle in PEM format. The value should either be the CA bundle as a string, alternatively as a file path.",
+ )
+
+ @model_validator(mode="after")
+ def set_tls_context(self) -> Self:
+ try:
+ # Validate that the context can be created, we want to raise this error during application start
+ # instead of running into issues later when we first try to use the tls context.
+ self.get_tls_context()
+ except ssl.SSLError as exc:
+ raise ValueError(f"Unable load CA bundle from {self.tls_ca_bundle}: {exc}") from exc
+
+ return self
+
+ def get_tls_context(self) -> ssl.SSLContext:
+ if self.tls_insecure:
+ return ssl._create_unverified_context()
+
+ if not self.tls_ca_bundle:
+ return ssl.create_default_context()
+
+ tls_ca_path = Path(self.tls_ca_bundle)
+
+ try:
+ possibly_file = tls_ca_path.exists()
+ except OSError:
+ # Raised if the filename is too long which can indicate
+ # that the value is a PEM certificate in string form.
+ possibly_file = False
+
+ if possibly_file and tls_ca_path.is_file():
+ context = ssl.create_default_context(cafile=str(tls_ca_path))
+ else:
+ context = ssl.create_default_context()
+ context.load_verify_locations(cadata=self.tls_ca_bundle)
+
+ return context
+
+
class InitialSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_INITIAL_")
default_branch: str = Field(
@@ -268,6 +408,85 @@ def check_tokens_match(self) -> Self:
return self
+def _default_scopes() -> list[str]:
+ return ["openid", "profile", "email"]
+
+
+class SecurityOIDCBaseSettings(BaseSettings):
+ """Baseclass for typing"""
+
+ icon: str = Field(default="mdi:account-key")
+ display_label: str = Field(default="Single Sign on")
+
+
+class SecurityOIDCSettings(SecurityOIDCBaseSettings):
+ client_id: str = Field(..., description="Client ID of the application created in the auth provider")
+ client_secret: str = Field(..., description="Client secret as defined in auth provider")
+ discovery_url: str = Field(..., description="The OIDC discovery URL xyz/.well-known/openid-configuration")
+ scopes: list[str] = Field(default_factory=_default_scopes)
+
+
+class SecurityOIDCGoogle(SecurityOIDCSettings):
+ """Settings for the custom OIDC provider"""
+
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_OIDC_GOOGLE_")
+
+ discovery_url: str = Field(default="https://accounts.google.com/.well-known/openid-configuration")
+ icon: str = Field(default="mdi:google")
+ display_label: str = Field(default="Google")
+
+
+class SecurityOIDCProvider1(SecurityOIDCSettings):
+ """Settings for the custom OIDC provider"""
+
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_OIDC_PROVIDER1_")
+
+
+class SecurityOIDCProvider2(SecurityOIDCSettings):
+ """Settings for the custom OIDC provider"""
+
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_OIDC_PROVIDER2_")
+
+
+class SecurityOAuth2BaseSettings(BaseSettings):
+ """Baseclass for typing"""
+
+ icon: str = Field(default="mdi:account-key")
+
+
+class SecurityOAuth2Settings(SecurityOAuth2BaseSettings):
+ """Common base for Oauth2 providers"""
+
+ client_id: str = Field(..., description="Client ID of the application created in the auth provider")
+ client_secret: str = Field(..., description="Client secret as defined in auth provider")
+ authorization_url: str = Field(...)
+ token_url: str = Field(...)
+ userinfo_url: str = Field(...)
+ scopes: list[str] = Field(default_factory=_default_scopes)
+ display_label: str = Field(default="Single Sign on")
+
+
+class SecurityOAuth2Provider1(SecurityOAuth2Settings):
+ """Common base for Oauth2 providers"""
+
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_OAUTH2_PROVIDER1_")
+
+
+class SecurityOAuth2Provider2(SecurityOAuth2Settings):
+ """Common base for Oauth2 providers"""
+
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_OAUTH2_PROVIDER2_")
+
+
+class SecurityOAuth2Google(SecurityOAuth2Settings):
+ model_config = SettingsConfigDict(env_prefix="INFRAHUB_OAUTH2_GOOGLE_")
+ authorization_url: str = Field(default="https://accounts.google.com/o/oauth2/auth")
+ token_url: str = Field(default="https://oauth2.googleapis.com/token")
+ userinfo_url: str = Field(default="https://www.googleapis.com/oauth2/v3/userinfo")
+ icon: str = Field(default="mdi:google")
+ display_label: str = Field(default="Google")
+
+
class MiscellaneousSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_MISC_")
print_query_details: bool = False
@@ -312,6 +531,72 @@ class SecuritySettings(BaseSettings):
secret_key: str = Field(
default_factory=generate_uuid, description="The secret key used to validate authentication tokens"
)
+ oauth2_providers: list[Oauth2Provider] = Field(default_factory=list, description="The selected OAuth2 providers")
+ oidc_providers: list[OIDCProvider] = Field(default_factory=list, description="The selected OIDC providers")
+ _oauth2_settings: dict[str, SecurityOAuth2Settings] = PrivateAttr(default_factory=dict)
+ _oidc_settings: dict[str, SecurityOIDCSettings] = PrivateAttr(default_factory=dict)
+
+ @model_validator(mode="after")
+ def check_oauth2_provider_settings(self) -> Self:
+ mapped_providers: dict[Oauth2Provider, type[SecurityOAuth2BaseSettings]] = {
+ Oauth2Provider.PROVIDER1: SecurityOAuth2Provider1,
+ Oauth2Provider.PROVIDER2: SecurityOAuth2Provider2,
+ Oauth2Provider.GOOGLE: SecurityOAuth2Google,
+ }
+ for oauth2_provider in self.oauth2_providers:
+ provider = mapped_providers[oauth2_provider]()
+ if isinstance(provider, SecurityOAuth2Settings):
+ self._oauth2_settings[oauth2_provider.value] = provider
+
+ return self
+
+ @model_validator(mode="after")
+ def check_oidc_provider_settings(self) -> Self:
+ mapped_providers: dict[OIDCProvider, type[SecurityOIDCBaseSettings]] = {
+ OIDCProvider.GOOGLE: SecurityOIDCGoogle,
+ OIDCProvider.PROVIDER1: SecurityOIDCProvider1,
+ OIDCProvider.PROVIDER2: SecurityOIDCProvider2,
+ }
+ for oidc_provider in self.oidc_providers:
+ provider = mapped_providers[oidc_provider]()
+ if isinstance(provider, SecurityOIDCSettings):
+ self._oidc_settings[oidc_provider.value] = provider
+
+ return self
+
+ def get_oauth2_provider(self, provider: str) -> SecurityOAuth2Settings:
+ if provider in self._oauth2_settings:
+ return self._oauth2_settings[provider]
+
+ raise ProcessingError(message=f"The provider {provider} has not been initialized")
+
+ def get_oidc_provider(self, provider: str) -> SecurityOIDCSettings:
+ if provider in self._oidc_settings:
+ return self._oidc_settings[provider]
+
+ raise ProcessingError(message=f"The provider {provider} has not been initialized")
+
+ @property
+ def public_sso_config(self) -> SSOInfo:
+ oauth2_providers = [
+ SSOProviderInfo(
+ name=provider,
+ display_label=self._oauth2_settings[provider].display_label,
+ icon=self._oauth2_settings[provider].icon,
+ protocol=SSOProtocol.OAUTH2,
+ )
+ for provider in self._oauth2_settings
+ ]
+ oidc_providers = [
+ SSOProviderInfo(
+ name=provider,
+ display_label=self._oidc_settings[provider].display_label,
+ icon=self._oidc_settings[provider].icon,
+ protocol=SSOProtocol.OIDC,
+ )
+ for provider in self._oidc_settings
+ ]
+ return SSOInfo(providers=oauth2_providers + oidc_providers)
class TraceSettings(BaseSettings):
@@ -333,10 +618,11 @@ class TraceSettings(BaseSettings):
class Override:
message_bus: Optional[InfrahubMessageBus] = None
cache: Optional[InfrahubCache] = None
+ workflow: Optional[InfrahubWorkflow] = None
@dataclass
-class ConfiguredSettings:
+class ConfiguredSettings: # pylint: disable=too-many-public-methods
settings: Optional[Settings] = None
def initialize(self, config_file: Optional[str] = None) -> None:
@@ -379,6 +665,10 @@ def api(self) -> ApiSettings:
def git(self) -> GitSettings:
return self.active_settings.git
+ @property
+ def http(self) -> HTTPSettings:
+ return self.active_settings.http
+
@property
def database(self) -> DatabaseSettings:
return self.active_settings.database
@@ -391,6 +681,14 @@ def broker(self) -> BrokerSettings:
def cache(self) -> CacheSettings:
return self.active_settings.cache
+ @property
+ def dev(self) -> DevelopmentSettings:
+ return self.active_settings.dev
+
+ @property
+ def workflow(self) -> WorkflowSettings:
+ return self.active_settings.workflow
+
@property
def miscellaneous(self) -> MiscellaneousSettings:
return self.active_settings.miscellaneous
@@ -430,9 +728,12 @@ class Settings(BaseSettings):
main: MainSettings = MainSettings()
api: ApiSettings = ApiSettings()
git: GitSettings = GitSettings()
+ dev: DevelopmentSettings = DevelopmentSettings()
+ http: HTTPSettings = HTTPSettings()
database: DatabaseSettings = DatabaseSettings()
broker: BrokerSettings = BrokerSettings()
cache: CacheSettings = CacheSettings()
+ workflow: WorkflowSettings = WorkflowSettings()
miscellaneous: MiscellaneousSettings = MiscellaneousSettings()
logging: LoggingSettings = LoggingSettings()
analytics: AnalyticsSettings = AnalyticsSettings()
diff --git a/backend/infrahub/core/account.py b/backend/infrahub/core/account.py
index 2402c4be83..1e629fe8b8 100644
--- a/backend/infrahub/core/account.py
+++ b/backend/infrahub/core/account.py
@@ -1,17 +1,216 @@
from __future__ import annotations
+from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Optional, Union
+from infrahub.core.constants import InfrahubKind
from infrahub.core.query import Query
from infrahub.core.registry import registry
if TYPE_CHECKING:
from infrahub.core.branch import Branch
from infrahub.database import InfrahubDatabase
+ from infrahub.permissions.constants import AssignedPermissions
+
# pylint: disable=redefined-builtin
+@dataclass
+class Permission:
+ id: str
+ name: str
+ action: str
+ decision: str
+
+
+@dataclass
+class GlobalPermission(Permission):
+ def __str__(self) -> str:
+ return f"global:{self.action}:{self.decision}"
+
+
+@dataclass
+class ObjectPermission(Permission):
+ branch: str
+ namespace: str
+
+ def __str__(self) -> str:
+ return f"object:{self.branch}:{self.namespace}:{self.name}:{self.action}:{self.decision}"
+
+
+class AccountGlobalPermissionQuery(Query):
+ name: str = "account_global_permissions"
+
+ def __init__(self, account_id: str, **kwargs: Any):
+ self.account_id = account_id
+ super().__init__(**kwargs)
+
+ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None:
+ self.params["account_id"] = self.account_id
+
+ branch_filter, branch_params = self.branch.get_query_filter_path(
+ at=self.at.to_string(), branch_agnostic=self.branch_agnostic
+ )
+ self.params.update(branch_params)
+
+ # ruff: noqa: E501
+ query = """
+ MATCH (account:%(generic_account_node)s)
+ WHERE account.uuid = $account_id
+ CALL {
+ WITH account
+ MATCH (account)-[r:IS_PART_OF]-(root:Root)
+ WHERE %(branch_filter)s
+ RETURN account as account1, r as r1
+ ORDER BY r.branch_level DESC, r.from DESC
+ LIMIT 1
+ }
+ WITH account, r1 as r
+ WHERE r.status = "active"
+ WITH account
+ MATCH group_path = (account)-[]->(:Relationship {name: "group_member"})
+ <-[]-(:%(group_node)s)
+ -[]->(:Relationship {name: "role__accountgroups"})
+ <-[]-(:%(account_role_node)s)
+ -[]->(:Relationship {name: "role__permissions"})
+ <-[]-(global_permission:%(global_permission_node)s)
+ -[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})
+ -[:HAS_VALUE]->(global_permission_name:AttributeValue)
+ WITH global_permission, global_permission_name
+ WHERE all(r IN relationships(group_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ MATCH action_path = (global_permission)-[:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[:HAS_VALUE]->(global_permission_action:AttributeValue)
+ WHERE all(r IN relationships(action_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ MATCH decision_path = (global_permission)-[:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[:HAS_VALUE]->(global_permission_decision:AttributeValue)
+ WHERE all(r IN relationships(decision_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ """ % {
+ "branch_filter": branch_filter,
+ "generic_account_node": InfrahubKind.GENERICACCOUNT,
+ "account_role_node": InfrahubKind.ACCOUNTROLE,
+ "group_node": InfrahubKind.ACCOUNTGROUP,
+ "global_permission_node": InfrahubKind.GLOBALPERMISSION,
+ }
+
+ self.add_to_query(query)
+
+ self.return_labels = [
+ "global_permission",
+ "global_permission_name",
+ "global_permission_action",
+ "global_permission_decision",
+ ]
+
+ def get_permissions(self) -> list[GlobalPermission]:
+ permissions: list[GlobalPermission] = []
+
+ for result in self.get_results():
+ permissions.append(
+ GlobalPermission(
+ id=result.get("global_permission").get("uuid"),
+ name=result.get("global_permission_name").get("value"),
+ action=result.get("global_permission_action").get("value"),
+ decision=result.get("global_permission_decision").get("value"),
+ )
+ )
+
+ return permissions
+
+
+class AccountObjectPermissionQuery(Query):
+ name: str = "account_object_permissions"
+
+ def __init__(self, account_id: str, **kwargs: Any):
+ self.account_id = account_id
+ super().__init__(**kwargs)
+
+ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None:
+ self.params["account_id"] = self.account_id
+
+ branch_filter, branch_params = self.branch.get_query_filter_path(
+ at=self.at.to_string(), branch_agnostic=self.branch_agnostic
+ )
+ self.params.update(branch_params)
+
+ query = """
+ MATCH (account:%(generic_account_node)s)
+ WHERE account.uuid = $account_id
+ CALL {
+ WITH account
+ MATCH (account)-[r:IS_PART_OF]-(root:Root)
+ WHERE %(branch_filter)s
+ RETURN account as account1, r as r1
+ ORDER BY r.branch_level DESC, r.from DESC
+ LIMIT 1
+ }
+ WITH account, r1 as r
+ WHERE r.status = "active"
+ WITH account
+ MATCH group_path = (account)-[]->(:Relationship {name: "group_member"})
+ <-[]-(:%(account_group_node)s)
+ -[]->(:Relationship {name: "role__accountgroups"})
+ <-[]-(:%(account_role_node)s)
+ -[]->(:Relationship {name: "role__permissions"})
+ <-[]-(object_permission:%(object_permission_node)s)
+ -[:HAS_ATTRIBUTE]->(:Attribute {name: "branch"})
+ -[:HAS_VALUE]->(object_permission_branch:AttributeValue)
+ WITH object_permission, object_permission_branch
+ WHERE all(r IN relationships(group_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ MATCH namespace_path = (object_permission)-[:HAS_ATTRIBUTE]->(:Attribute {name: "namespace"})-[:HAS_VALUE]->(object_permission_namespace:AttributeValue)
+ WHERE all(r IN relationships(namespace_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ MATCH name_path = (object_permission)-[:HAS_ATTRIBUTE]->(:Attribute {name: "name"})-[:HAS_VALUE]->(object_permission_name:AttributeValue)
+ WHERE all(r IN relationships(name_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ MATCH action_path = (object_permission)-[:HAS_ATTRIBUTE]->(:Attribute {name: "action"})-[:HAS_VALUE]->(object_permission_action:AttributeValue)
+ WHERE all(r IN relationships(action_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ MATCH decision_path = (object_permission)-[:HAS_ATTRIBUTE]->(:Attribute {name: "decision"})-[:HAS_VALUE]->(object_permission_decision:AttributeValue)
+ WHERE all(r IN relationships(decision_path) WHERE (%(branch_filter)s) AND r.status = "active")
+ """ % {
+ "branch_filter": branch_filter,
+ "account_group_node": InfrahubKind.ACCOUNTGROUP,
+ "account_role_node": InfrahubKind.ACCOUNTROLE,
+ "generic_account_node": InfrahubKind.GENERICACCOUNT,
+ "object_permission_node": InfrahubKind.OBJECTPERMISSION,
+ }
+
+ self.add_to_query(query)
+
+ self.return_labels = [
+ "object_permission",
+ "object_permission_branch",
+ "object_permission_namespace",
+ "object_permission_name",
+ "object_permission_action",
+ "object_permission_decision",
+ ]
+
+ def get_permissions(self) -> list[ObjectPermission]:
+ permissions: list[ObjectPermission] = []
+ for result in self.get_results():
+ permissions.append(
+ ObjectPermission(
+ id=result.get("object_permission").get("uuid"),
+ branch=result.get("object_permission_branch").get("value"),
+ namespace=result.get("object_permission_namespace").get("value"),
+ name=result.get("object_permission_name").get("value"),
+ action=result.get("object_permission_action").get("value"),
+ decision=result.get("object_permission_decision").get("value"),
+ )
+ )
+
+ return permissions
+
+
+async def fetch_permissions(account_id: str, db: InfrahubDatabase, branch: Branch) -> AssignedPermissions:
+ query1 = await AccountGlobalPermissionQuery.init(db=db, branch=branch, account_id=account_id, branch_agnostic=True)
+ await query1.execute(db=db)
+ global_permissions = query1.get_permissions()
+
+ query2 = await AccountObjectPermissionQuery.init(db=db, branch=branch, account_id=account_id)
+ await query2.execute(db=db)
+ object_permissions = query2.get_permissions()
+
+ return {"global_permissions": global_permissions, "object_permissions": object_permissions}
+
+
class AccountTokenValidateQuery(Query):
name: str = "account_token_validate"
diff --git a/backend/infrahub/core/attribute.py b/backend/infrahub/core/attribute.py
index a661c7d5b1..5074e10ea2 100644
--- a/backend/infrahub/core/attribute.py
+++ b/backend/infrahub/core/attribute.py
@@ -151,7 +151,7 @@ def get_branch_based_on_support_type(self) -> Branch:
return self.branch
@classmethod
- def __init_subclass__(cls, **kwargs):
+ def __init_subclass__(cls, **kwargs) -> None:
super().__init_subclass__(**kwargs)
registry.attribute[cls.__name__] = cls
@@ -549,7 +549,7 @@ async def from_graphql(self, data: dict, db: InfrahubDatabase) -> bool:
return changed
- def get_db_node_type(self):
+ def get_db_node_type(self) -> AttributeDBNodeType:
return AttributeDBNodeType.DEFAULT
def get_create_data(self) -> AttributeCreateData:
@@ -840,7 +840,7 @@ def serialize_value(self) -> str:
return ipaddress.ip_network(str(self.value)).with_prefixlen
- def get_db_node_type(self):
+ def get_db_node_type(self) -> AttributeDBNodeType:
if self.value is not None:
return AttributeDBNodeType.IPNETWORK
return AttributeDBNodeType.DEFAULT
@@ -966,7 +966,7 @@ def serialize_value(self) -> str:
return ipaddress.ip_interface(str(self.value)).with_prefixlen
- def get_db_node_type(self):
+ def get_db_node_type(self) -> AttributeDBNodeType:
if self.value is not None:
return AttributeDBNodeType.IPHOST
return AttributeDBNodeType.DEFAULT
diff --git a/backend/infrahub/core/constants/__init__.py b/backend/infrahub/core/constants/__init__.py
index 6bb1f4195c..d3a5e57e87 100644
--- a/backend/infrahub/core/constants/__init__.py
+++ b/backend/infrahub/core/constants/__init__.py
@@ -9,12 +9,12 @@
from .schema import FlagProperty, NodeProperty, SchemaElementPathType, UpdateSupport, UpdateValidationErrorType
__all__ = [
- "InfrahubKind",
"FlagProperty",
+ "InfrahubKind",
"NodeProperty",
+ "SchemaElementPathType",
"UpdateSupport",
"UpdateValidationErrorType",
- "SchemaElementPathType",
]
@@ -50,6 +50,29 @@ class PermissionLevel(enum.Flag):
DEFAULT = 0
+class GlobalPermissions(InfrahubStringEnum):
+ EDIT_DEFAULT_BRANCH = "edit_default_branch"
+ SUPER_ADMIN = "super_admin"
+ MERGE_BRANCH = "merge_branch"
+ MERGE_PROPOSED_CHANGE = "merge_proposed_change"
+ MANAGE_ACCOUNTS = "manage_accounts"
+ MANAGE_PERMISSIONS = "manage_permissions"
+ MANAGE_REPOSITORIES = "manage_repositories"
+
+
+class PermissionAction(InfrahubStringEnum):
+ ANY = "any"
+ ADD = "create"
+ CHANGE = "update"
+ DELETE = "delete"
+ VIEW = "view"
+
+
+class PermissionDecision(InfrahubStringEnum):
+ ALLOW = "allow"
+ DENY = "deny"
+
+
class AccountRole(InfrahubStringEnum):
ADMIN = "admin"
READ_ONLY = "read-only"
@@ -175,16 +198,6 @@ def from_relationship(cls, relationship: RelationshipCardinality) -> PathType:
return cls("relationship_many")
-class FilterSchemaKind(InfrahubStringEnum):
- TEXT = "Text"
- LIST = "Text"
- NUMBER = "Number"
- BOOLEAN = "Boolean"
- OBJECT = "Object"
- MULTIOBJECT = "MultiObject"
- ENUM = "Enum"
-
-
class ProposedChangeState(InfrahubStringEnum):
OPEN = "open"
MERGED = "merged"
diff --git a/backend/infrahub/core/constants/infrahubkind.py b/backend/infrahub/core/constants/infrahubkind.py
index 904371b510..bc2f8229f6 100644
--- a/backend/infrahub/core/constants/infrahubkind.py
+++ b/backend/infrahub/core/constants/infrahubkind.py
@@ -1,4 +1,6 @@
ACCOUNT = "CoreAccount"
+ACCOUNTGROUP = "CoreAccountGroup"
+ACCOUNTROLE = "CoreAccountRole"
ACCOUNTTOKEN = "InternalAccountToken"
ARTIFACT = "CoreArtifact"
ARTIFACTCHECK = "CoreArtifactCheck"
@@ -6,6 +8,7 @@
ARTIFACTTARGET = "CoreArtifactTarget"
ARTIFACTTHREAD = "CoreArtifactThread"
ARTIFACTVALIDATOR = "CoreArtifactValidator"
+BASEPERMISSION = "CoreBasePermission"
CHANGECOMMENT = "CoreChangeComment"
CHANGETHREAD = "CoreChangeThread"
CHECKDEFINITION = "CoreCheckDefinition"
@@ -23,6 +26,7 @@
GENERATORVALIDATOR = "CoreGeneratorValidator"
GENERATORGROUP = "CoreGeneratorGroup"
GENERICGROUP = "CoreGroup"
+GLOBALPERMISSION = "CoreGlobalPermission"
GRAPHQLQUERY = "CoreGraphQLQuery"
GRAPHQLQUERYGROUP = "CoreGraphQLQueryGroup"
IPNAMESPACE = "BuiltinIPNamespace"
@@ -30,11 +34,13 @@
IPADDRESSPOOL = "CoreIPAddressPool"
IPPREFIX = "BuiltinIPPrefix"
IPPREFIXPOOL = "CoreIPPrefixPool"
+MENUITEM = "CoreMenuItem"
NAMESPACE = "IpamNamespace"
NODE = "CoreNode"
NUMBERPOOL = "CoreNumberPool"
LINEAGEOWNER = "LineageOwner"
LINEAGESOURCE = "LineageSource"
+OBJECTPERMISSION = "CoreObjectPermission"
OBJECTTHREAD = "CoreObjectThread"
PASSWORDCREDENTIAL = "CorePasswordCredential"
PROFILE = "CoreProfile"
diff --git a/backend/infrahub/core/diff/branch_differ.py b/backend/infrahub/core/diff/branch_differ.py
index 30bfb06cc9..240823b261 100644
--- a/backend/infrahub/core/diff/branch_differ.py
+++ b/backend/infrahub/core/diff/branch_differ.py
@@ -278,7 +278,7 @@ async def get_conflicts_graph(self) -> list[DataConflict]:
property_name=conflict.property_name,
)
for branch, change in changes.items():
- if response.path in change and change[response.path]:
+ if change.get(response.path):
response.changes.append(
BranchChanges(
branch=branch,
diff --git a/backend/infrahub/core/diff/combiner.py b/backend/infrahub/core/diff/combiner.py
index 67ecc7bb14..584c70265b 100644
--- a/backend/infrahub/core/diff/combiner.py
+++ b/backend/infrahub/core/diff/combiner.py
@@ -108,7 +108,7 @@ def _combine_actions(self, earlier: DiffAction, later: DiffAction) -> DiffAction
(DiffAction.REMOVED, DiffAction.ADDED): DiffAction.UPDATED,
(DiffAction.REMOVED, DiffAction.UPDATED): DiffAction.UPDATED,
}
- return actions_map[(earlier, later)]
+ return actions_map[earlier, later]
@staticmethod
def combine_conflicts(
@@ -155,6 +155,15 @@ def _combine_properties(
conflict=combined_conflict,
)
)
+ combined_properties.add(
+ replace(
+ later_property,
+ previous_label=earlier_property.previous_label,
+ previous_value=earlier_property.previous_value,
+ action=self._combine_actions(earlier=earlier_property.action, later=later_property.action),
+ conflict=combined_conflict,
+ )
+ )
combined_properties |= {
deepcopy(prop) for prop in later_properties if prop.property_type not in common_property_types
}
diff --git a/backend/infrahub/core/diff/coordinator.py b/backend/infrahub/core/diff/coordinator.py
index cc334cb857..c725222fd9 100644
--- a/backend/infrahub/core/diff/coordinator.py
+++ b/backend/infrahub/core/diff/coordinator.py
@@ -343,11 +343,12 @@ def _get_missing_time_ranges(
return missing_time_ranges
def _get_node_field_specifiers(self, enriched_diff: EnrichedDiffRoot) -> set[NodeFieldSpecifier]:
- specifiers = set()
+ specifiers: set[NodeFieldSpecifier] = set()
schema_branch = registry.schema.get_schema_branch(name=enriched_diff.diff_branch_name)
for node in enriched_diff.nodes:
- for attribute in node.attributes:
- specifiers.add(NodeFieldSpecifier(node_uuid=node.uuid, field_name=attribute.name))
+ specifiers.update(
+ NodeFieldSpecifier(node_uuid=node.uuid, field_name=attribute.name) for attribute in node.attributes
+ )
if not node.relationships:
continue
node_schema = schema_branch.get_node(name=node.kind, duplicate=False)
diff --git a/sync/examples/infrahub_to_peering-manager/infrahub/__init__.py b/backend/infrahub/core/diff/merger/__init__.py
similarity index 100%
rename from sync/examples/infrahub_to_peering-manager/infrahub/__init__.py
rename to backend/infrahub/core/diff/merger/__init__.py
diff --git a/backend/infrahub/core/diff/merger/merger.py b/backend/infrahub/core/diff/merger/merger.py
new file mode 100644
index 0000000000..0792f2549f
--- /dev/null
+++ b/backend/infrahub/core/diff/merger/merger.py
@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from infrahub.core.diff.model.path import BranchTrackingId
+from infrahub.core.diff.query.merge import DiffMergeQuery
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.diff.repository.repository import DiffRepository
+ from infrahub.core.timestamp import Timestamp
+ from infrahub.database import InfrahubDatabase
+
+ from .serializer import DiffMergeSerializer
+
+
+class DiffMerger:
+ def __init__(
+ self,
+ db: InfrahubDatabase,
+ source_branch: Branch,
+ destination_branch: Branch,
+ diff_repository: DiffRepository,
+ serializer: DiffMergeSerializer,
+ ):
+ self.source_branch = source_branch
+ self.destination_branch = destination_branch
+ self.db = db
+ self.diff_repository = diff_repository
+ self.serializer = serializer
+
+ async def merge_graph(self, at: Timestamp) -> None:
+ enriched_diff = await self.diff_repository.get_one(
+ diff_branch_name=self.source_branch.name, tracking_id=BranchTrackingId(name=self.source_branch.name)
+ )
+ node_diff_dicts = await self.serializer.serialize(diff=enriched_diff)
+ merge_query = await DiffMergeQuery.init(
+ db=self.db,
+ branch=self.source_branch,
+ at=at,
+ target_branch=self.destination_branch,
+ node_diff_dicts=node_diff_dicts,
+ )
+ await merge_query.execute(db=self.db)
+
+ self.source_branch.branched_from = at.to_string()
+ await self.source_branch.save(db=self.db)
diff --git a/backend/infrahub/core/diff/merger/serializer.py b/backend/infrahub/core/diff/merger/serializer.py
new file mode 100644
index 0000000000..52aad8ad28
--- /dev/null
+++ b/backend/infrahub/core/diff/merger/serializer.py
@@ -0,0 +1,28 @@
+from typing import Any
+
+from infrahub.core.constants import DiffAction
+
+from ..model.path import ConflictSelection, EnrichedDiffConflict, EnrichedDiffRoot
+
+
+class DiffMergeSerializer:
+ def _get_action(self, action: DiffAction, conflict: EnrichedDiffConflict | None) -> DiffAction:
+ if not conflict:
+ return action
+ if conflict.selected_branch is ConflictSelection.BASE_BRANCH:
+ return conflict.base_branch_action
+ if conflict.selected_branch is ConflictSelection.DIFF_BRANCH:
+ return conflict.diff_branch_action
+ raise ValueError(f"conflict {conflict.uuid} does not have a branch selection")
+
+ async def serialize(self, diff: EnrichedDiffRoot) -> list[dict[str, Any]]:
+ serialized_node_diffs = []
+ for node in diff.nodes:
+ node_action = self._get_action(action=node.action, conflict=node.conflict)
+ serialized_node_diffs.append(
+ {
+ "action": str(node_action.value).upper(),
+ "uuid": node.uuid,
+ }
+ )
+ return serialized_node_diffs
diff --git a/backend/infrahub/core/diff/model/path.py b/backend/infrahub/core/diff/model/path.py
index 5fb902d0c4..617de15777 100644
--- a/backend/infrahub/core/diff/model/path.py
+++ b/backend/infrahub/core/diff/model/path.py
@@ -15,7 +15,7 @@
from neo4j.graph import Path as Neo4jPath
from neo4j.graph import Relationship as Neo4jRelationship
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
@dataclass
diff --git a/backend/infrahub/core/diff/query/merge.py b/backend/infrahub/core/diff/query/merge.py
new file mode 100644
index 0000000000..b9084431db
--- /dev/null
+++ b/backend/infrahub/core/diff/query/merge.py
@@ -0,0 +1,95 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from infrahub.core.query import Query, QueryType
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.timestamp import Timestamp
+ from infrahub.database import InfrahubDatabase
+
+
+class DiffMergeQuery(Query):
+ name = "diff_merge"
+ type = QueryType.WRITE
+ insert_return = False
+
+ def __init__(
+ self,
+ node_diff_dicts: dict[str, Any],
+ at: Timestamp,
+ target_branch: Branch,
+ **kwargs: Any,
+ ) -> None:
+ super().__init__(**kwargs)
+ self.node_diff_dicts = node_diff_dicts
+ self.at = at
+ self.target_branch = target_branch
+ self.source_branch_name = self.branch.name
+
+ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None:
+ self.params = {
+ "node_diff_dicts": self.node_diff_dicts,
+ "at": self.at.to_string(),
+ "branch_level": self.target_branch.hierarchy_level,
+ "target_branch": self.target_branch.name,
+ "source_branch": self.source_branch_name,
+ }
+ query = """
+UNWIND $node_diff_dicts AS node_diff_map
+CALL {
+ WITH node_diff_map
+ WITH node_diff_map, CASE
+ WHEN node_diff_map.action = "ADDED" THEN "active"
+ WHEN node_diff_map.action = "REMOVED" THEN "deleted"
+ ELSE NULL
+ END AS node_rel_status
+ CALL {
+ // ------------------------------
+ // only make IS_PART_OF updates if node is ADDED or REMOVED
+ // ------------------------------
+ WITH node_diff_map, node_rel_status
+ WITH node_diff_map, node_rel_status
+ WHERE node_rel_status IS NOT NULL
+ MATCH (root:Root)
+ MATCH (n:Node {uuid: node_diff_map.uuid})
+ // ------------------------------
+ // check if IS_PART_OF relationship with node_rel_status already exists on the target branch
+ // ------------------------------
+ CALL {
+ WITH root, n, node_rel_status
+ OPTIONAL MATCH (root)<-[r_root:IS_PART_OF {branch: $target_branch}]-(n)
+ WHERE r_root.status = node_rel_status
+ AND r_root.from <= $at
+ AND (r_root.to >= $at OR r_root.to IS NULL)
+ RETURN r_root
+ }
+ // ------------------------------
+ // set IS_PART_OF.to on source branch and, optionally, target branch
+ // ------------------------------
+ WITH root, r_root, n, node_rel_status
+ CALL {
+ WITH root, n, node_rel_status
+ OPTIONAL MATCH (root)<-[source_r_root:IS_PART_OF {branch: $source_branch, status: node_rel_status}]-(n)
+ WHERE source_r_root.from <= $at AND source_r_root.to IS NULL
+ SET source_r_root.to = $at
+ }
+ WITH root, r_root, n, node_rel_status
+ CALL {
+ WITH root, n, node_rel_status
+ OPTIONAL MATCH (root)<-[target_r_root:IS_PART_OF {branch: $target_branch, status: "active"}]-(n)
+ WHERE node_rel_status = "deleted"
+ AND target_r_root.from <= $at AND target_r_root.to IS NULL
+ SET target_r_root.to = $at
+ }
+ // ------------------------------
+ // create new IS_PART_OF relationship on target_branch
+ // ------------------------------
+ WITH root, r_root, n, node_rel_status
+ WHERE r_root IS NULL
+ CREATE (root)<-[:IS_PART_OF { branch: $target_branch, branch_level: $branch_level, from: $at, status: node_rel_status }]-(n)
+ }
+}
+ """
+ self.add_to_query(query=query)
diff --git a/backend/infrahub/core/diff/query_parser.py b/backend/infrahub/core/diff/query_parser.py
index 367ccd0a5b..f3606f34e7 100644
--- a/backend/infrahub/core/diff/query_parser.py
+++ b/backend/infrahub/core/diff/query_parser.py
@@ -22,8 +22,8 @@
if TYPE_CHECKING:
from infrahub.core.branch import Branch
from infrahub.core.query import QueryResult
+ from infrahub.core.schema.manager import SchemaManager
from infrahub.core.schema.relationship_schema import RelationshipSchema
- from infrahub.core.schema_manager import SchemaManager
class DiffNoChildPathError(Exception): ...
@@ -447,15 +447,17 @@ def get_diff_root_for_branch(self, branch: str) -> DiffRoot:
def get_node_field_specifiers_for_branch(self, branch_name: str) -> set[NodeFieldSpecifier]:
if branch_name not in self._diff_root_by_branch:
return set()
- node_field_specifiers = set()
+ node_field_specifiers: set[NodeFieldSpecifier] = set()
diff_root = self._diff_root_by_branch[branch_name]
for node in diff_root.nodes_by_id.values():
- for attribute_name in node.attributes_by_name:
- node_field_specifiers.add(NodeFieldSpecifier(node_uuid=node.uuid, field_name=attribute_name))
- for relationship_diff in node.relationships_by_name.values():
- node_field_specifiers.add(
- NodeFieldSpecifier(node_uuid=node.uuid, field_name=relationship_diff.identifier)
- )
+ node_field_specifiers.update(
+ NodeFieldSpecifier(node_uuid=node.uuid, field_name=attribute_name)
+ for attribute_name in node.attributes_by_name
+ )
+ node_field_specifiers.update(
+ NodeFieldSpecifier(node_uuid=node.uuid, field_name=relationship_diff.identifier)
+ for relationship_diff in node.relationships_by_name.values()
+ )
return node_field_specifiers
def read_result(self, query_result: QueryResult) -> None:
diff --git a/backend/infrahub/core/initialization.py b/backend/infrahub/core/initialization.py
index 1c3d5b3b8a..eef11ef412 100644
--- a/backend/infrahub/core/initialization.py
+++ b/backend/infrahub/core/initialization.py
@@ -1,23 +1,37 @@
+import importlib
from typing import Optional
from uuid import uuid4
from infrahub import config, lock
from infrahub.core import registry
from infrahub.core.branch import Branch
-from infrahub.core.constants import DEFAULT_IP_NAMESPACE, GLOBAL_BRANCH_NAME, AccountRole, InfrahubKind
+from infrahub.core.constants import (
+ DEFAULT_IP_NAMESPACE,
+ GLOBAL_BRANCH_NAME,
+ AccountRole,
+ GlobalPermissions,
+ InfrahubKind,
+ PermissionDecision,
+)
from infrahub.core.graph import GRAPH_VERSION
from infrahub.core.node import Node
from infrahub.core.node.ipam import BuiltinIPPrefix
+from infrahub.core.node.permissions import CoreGlobalPermission, CoreObjectPermission
from infrahub.core.node.resource_manager.ip_address_pool import CoreIPAddressPool
from infrahub.core.node.resource_manager.ip_prefix_pool import CoreIPPrefixPool
from infrahub.core.node.resource_manager.number_pool import CoreNumberPool
+from infrahub.core.protocols import CoreAccount, CoreMenuItem
from infrahub.core.root import Root
from infrahub.core.schema import SchemaRoot, core_models, internal_schema
-from infrahub.core.schema_manager import SchemaManager
+from infrahub.core.schema.manager import SchemaManager
from infrahub.database import InfrahubDatabase
from infrahub.exceptions import DatabaseError
from infrahub.log import get_logger
+from infrahub.menu.menu import default_menu
+from infrahub.menu.models import MenuItemDefinition
+from infrahub.permissions import PermissionBackend
from infrahub.storage import InfrahubObjectStorage
+from infrahub.utils import format_label
log = get_logger()
@@ -53,6 +67,18 @@ async def get_default_ipnamespace(db: InfrahubDatabase) -> Optional[Node]:
return nodes[0]
+def initialize_permission_backends() -> list[PermissionBackend]:
+ permission_backends: list[PermissionBackend] = []
+ for backend_module_path in config.SETTINGS.main.permission_backends:
+ log.info("Loading permission backend", backend=backend_module_path)
+
+ module, class_name = backend_module_path.rsplit(".", maxsplit=1)
+ Backend = getattr(importlib.import_module(module), class_name)
+ permission_backends.append(Backend())
+
+ return permission_backends
+
+
async def initialize_registry(db: InfrahubDatabase, initialize: bool = False) -> None:
# ---------------------------------------------------
# Initialize the database and Load the Root node
@@ -81,6 +107,13 @@ async def initialize_registry(db: InfrahubDatabase, initialize: bool = False) ->
registry.node[InfrahubKind.IPADDRESSPOOL] = CoreIPAddressPool
registry.node[InfrahubKind.IPPREFIXPOOL] = CoreIPPrefixPool
registry.node[InfrahubKind.NUMBERPOOL] = CoreNumberPool
+ registry.node[InfrahubKind.GLOBALPERMISSION] = CoreGlobalPermission
+ registry.node[InfrahubKind.OBJECTPERMISSION] = CoreObjectPermission
+
+ # ---------------------------------------------------
+ # Instantiate permission backends
+ # ---------------------------------------------------
+ registry.permission_backends = initialize_permission_backends()
async def initialization(db: InfrahubDatabase) -> None:
@@ -233,9 +266,9 @@ async def create_account(
role: str = "admin",
password: Optional[str] = None,
token_value: Optional[str] = None,
-) -> Node:
+) -> CoreAccount:
token_schema = db.schema.get_node_schema(name=InfrahubKind.ACCOUNTTOKEN)
- obj = await Node.init(db=db, schema=InfrahubKind.ACCOUNT)
+ obj = await Node.init(db=db, schema=CoreAccount)
await obj.new(db=db, name=name, account_type="User", role=role, password=password)
await obj.save(db=db)
log.info(f"Created Account: {name}", account_name=name)
@@ -261,6 +294,72 @@ async def create_ipam_namespace(
return obj
+async def create_initial_permission(db: InfrahubDatabase) -> Node:
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db,
+ name=format_label(GlobalPermissions.SUPER_ADMIN.value),
+ action=GlobalPermissions.SUPER_ADMIN.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ await permission.save(db=db)
+ log.info(f"Created global permission: {GlobalPermissions.SUPER_ADMIN}")
+ return permission
+
+
+async def create_menu_children(db: InfrahubDatabase, parent: CoreMenuItem, children: list[MenuItemDefinition]) -> None:
+ for child in children:
+ obj = await child.to_node(db=db, parent=parent)
+ await obj.save(db=db)
+ if child.children:
+ await create_menu_children(db=db, parent=obj, children=child.children)
+
+
+async def create_default_menu(db: InfrahubDatabase) -> None:
+ for item in default_menu:
+ obj = await item.to_node(db=db)
+ await obj.save(db=db)
+ if item.children:
+ await create_menu_children(db=db, parent=obj, children=item.children)
+
+
+async def create_super_administrator_role(db: InfrahubDatabase) -> Node:
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db,
+ name=format_label(GlobalPermissions.SUPER_ADMIN.value),
+ action=GlobalPermissions.SUPER_ADMIN.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ await permission.save(db=db)
+ log.info(f"Created global permission: {GlobalPermissions.SUPER_ADMIN}")
+
+ role_name = "Super Administrator"
+ obj = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await obj.new(db=db, name=role_name, permissions=[permission])
+ await obj.save(db=db)
+ log.info(f"Created account role: {role_name}")
+
+ return obj
+
+
+async def create_super_administrators_group(
+ db: InfrahubDatabase, role: Node, admin_accounts: list[CoreAccount]
+) -> Node:
+ group_name = "Super Administrators"
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name=group_name, roles=[role])
+ await group.save(db=db)
+ log.info(f"Created account group: {group_name}")
+
+ for admin_account in admin_accounts:
+ await group.members.add(db=db, data=admin_account) # type: ignore[attr-defined]
+ await group.members.save(db=db) # type: ignore[attr-defined]
+ log.info(f"Assigned account group: {group_name} to {admin_account.name.value}")
+
+ return group
+
+
async def first_time_initialization(db: InfrahubDatabase) -> None:
# --------------------------------------------------
# Create the default Branch
@@ -283,27 +382,43 @@ async def first_time_initialization(db: InfrahubDatabase) -> None:
await default_branch.save(db=db)
log.info("Created the Schema in the database", hash=default_branch.active_schema_hash.main)
+ # --------------------------------------------------
+ # Create Default Menu
+ # --------------------------------------------------
+ await create_default_menu(db=db)
+
# --------------------------------------------------
# Create Default Users and Groups
# --------------------------------------------------
- await create_account(
- db=db,
- name="admin",
- password=config.SETTINGS.initial.admin_password,
- token_value=config.SETTINGS.initial.admin_token,
+ admin_accounts: list[CoreAccount] = []
+ admin_accounts.append(
+ await create_account(
+ db=db,
+ name="admin",
+ password=config.SETTINGS.initial.admin_password,
+ token_value=config.SETTINGS.initial.admin_token,
+ )
)
if config.SETTINGS.initial.create_agent_user:
password = config.SETTINGS.initial.agent_password or str(uuid4())
- await create_account(
- db=db,
- name="agent",
- password=password,
- role=AccountRole.READ_WRITE.value,
- token_value=config.SETTINGS.initial.agent_token,
+ admin_accounts.append(
+ await create_account(
+ db=db,
+ name="agent",
+ password=password,
+ role=AccountRole.READ_WRITE.value,
+ token_value=config.SETTINGS.initial.agent_token,
+ )
)
+ # --------------------------------------------------
+ # Create Global Permissions and assign them
+ # --------------------------------------------------
+ administrator_role = await create_super_administrator_role(db=db)
+ await create_super_administrators_group(db=db, role=administrator_role, admin_accounts=admin_accounts)
+
# --------------------------------------------------
# Create Default IPAM Namespace
# --------------------------------------------------
diff --git a/backend/infrahub/core/ipam/utilization.py b/backend/infrahub/core/ipam/utilization.py
index 7b48ce9cf4..da85b79293 100644
--- a/backend/infrahub/core/ipam/utilization.py
+++ b/backend/infrahub/core/ipam/utilization.py
@@ -75,7 +75,7 @@ async def get_children(
return prefix_child_details_list
for prefix_id in prefix_ids:
child_details_by_branch = self._results_by_prefix_id[prefix_id]
- branch_names_to_check = branch_names if branch_names else list(child_details_by_branch.keys())
+ branch_names_to_check = branch_names or list(child_details_by_branch.keys())
for branch_name in branch_names_to_check:
for child_details in child_details_by_branch.get(branch_name, []):
if prefix_member_type and child_details.child_type != prefix_member_type:
diff --git a/backend/infrahub/core/manager.py b/backend/infrahub/core/manager.py
index a40d0cbc3e..495b2994d6 100644
--- a/backend/infrahub/core/manager.py
+++ b/backend/infrahub/core/manager.py
@@ -71,7 +71,7 @@ def __init__(
self,
profile_attributes_id_map: dict[str, NodeAttributesFromDB],
profile_ids_by_node_id: dict[str, list[str]],
- ):
+ ) -> None:
self._profile_attributes_id_map = profile_attributes_id_map
self._profile_ids_by_node_id = profile_ids_by_node_id
@@ -1043,21 +1043,28 @@ async def get_one(
node = result[id]
node_schema = node.get_schema()
+ kind_validation = None
+ if kind:
+ node_schema_validation = get_schema(db=db, branch=branch, node_schema=kind)
+ kind_validation = node_schema_validation.kind
+
# Temporary list of exception to the validation of the kind
kind_validation_exceptions = [
("CoreChangeThread", "CoreObjectThread"), # issue/3318
]
- if kind and (node_schema.kind != kind and kind not in node_schema.inherit_from):
+ if kind_validation and (
+ node_schema.kind != kind_validation and kind_validation not in node_schema.inherit_from
+ ):
for item in kind_validation_exceptions:
- if item[0] == kind and item[1] == node.get_kind():
+ if item[0] == kind_validation and item[1] == node.get_kind():
return node
raise NodeNotFoundError(
branch_name=branch.name,
- node_type=kind,
+ node_type=kind_validation,
identifier=id,
- message=f"Node with id {id} exists, but it is a {node.get_kind()}, not {kind}",
+ message=f"Node with id {id} exists, but it is a {node.get_kind()}, not {kind_validation}",
)
return node
diff --git a/backend/infrahub/core/merge.py b/backend/infrahub/core/merge.py
index 49ec1c5645..818ea38de2 100644
--- a/backend/infrahub/core/merge.py
+++ b/backend/infrahub/core/merge.py
@@ -4,7 +4,7 @@
from infrahub.core.constants import DiffAction, RelationshipStatus, RepositoryInternalStatus
from infrahub.core.manager import NodeManager
-from infrahub.core.models import SchemaBranchDiff
+from infrahub.core.models import SchemaBranchDiff, SchemaUpdateValidationResult
from infrahub.core.protocols import CoreRepository
from infrahub.core.query.branch import (
AddNodeToBranch,
@@ -12,7 +12,6 @@
from infrahub.core.query.node import NodeDeleteQuery, NodeListGetInfoQuery
from infrahub.core.registry import registry
from infrahub.core.schema import GenericSchema, NodeSchema
-from infrahub.core.schema_manager import SchemaUpdateValidationResult
from infrahub.core.timestamp import Timestamp
from infrahub.core.utils import add_relationship, update_relationships_to
from infrahub.exceptions import ValidationError
@@ -23,7 +22,8 @@
if TYPE_CHECKING:
from infrahub.core.branch import Branch
from infrahub.core.models import SchemaUpdateConstraintInfo, SchemaUpdateMigrationInfo
- from infrahub.core.schema_manager import SchemaBranch, SchemaDiff
+ from infrahub.core.schema.manager import SchemaDiff
+ from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
from infrahub.services import InfrahubServices
diff --git a/backend/infrahub/core/migrations/graph/m012_convert_account_generic.py b/backend/infrahub/core/migrations/graph/m012_convert_account_generic.py
index c26f42d95b..37c49b1556 100644
--- a/backend/infrahub/core/migrations/graph/m012_convert_account_generic.py
+++ b/backend/infrahub/core/migrations/graph/m012_convert_account_generic.py
@@ -5,7 +5,7 @@
from infrahub.core.branch import Branch
from infrahub.core.constants import GLOBAL_BRANCH_NAME, BranchSupportType, InfrahubKind
from infrahub.core.migrations.shared import MigrationResult
-from infrahub.core.query import Query, QueryType # noqa: TCH001
+from infrahub.core.query import Query, QueryType
from ..query.attribute_rename import AttributeInfo, AttributeRenameQuery
from ..query.delete_element_in_schema import DeleteElementInSchemaQuery
diff --git a/backend/infrahub/core/migrations/query/schema_attribute_update.py b/backend/infrahub/core/migrations/query/schema_attribute_update.py
index f3e488c8d7..1a52cdbfbf 100644
--- a/backend/infrahub/core/migrations/query/schema_attribute_update.py
+++ b/backend/infrahub/core/migrations/query/schema_attribute_update.py
@@ -4,7 +4,7 @@
import ujson
-from infrahub.core.query import Query, QueryType # noqa: TCH001
+from infrahub.core.query import Query, QueryType
from infrahub.core.timestamp import Timestamp
if TYPE_CHECKING:
diff --git a/backend/infrahub/core/migrations/schema/models.py b/backend/infrahub/core/migrations/schema/models.py
new file mode 100644
index 0000000000..16e0a7fad5
--- /dev/null
+++ b/backend/infrahub/core/migrations/schema/models.py
@@ -0,0 +1,15 @@
+from pydantic import BaseModel, ConfigDict
+
+from infrahub.core.branch import Branch
+from infrahub.core.models import SchemaUpdateMigrationInfo
+from infrahub.core.schema.schema_branch import SchemaBranch
+
+
+class SchemaApplyMigrationData(BaseModel):
+ model_config = ConfigDict(
+ arbitrary_types_allowed=True, json_encoders={SchemaBranch: SchemaBranch.to_dict_schema_object}
+ )
+ branch: Branch
+ new_schema: SchemaBranch
+ previous_schema: SchemaBranch
+ migrations: list[SchemaUpdateMigrationInfo]
diff --git a/backend/infrahub/core/migrations/schema/runner.py b/backend/infrahub/core/migrations/schema/runner.py
index 49a83ea9b5..8ebd66fb19 100644
--- a/backend/infrahub/core/migrations/schema/runner.py
+++ b/backend/infrahub/core/migrations/schema/runner.py
@@ -3,13 +3,16 @@
import asyncio
from typing import TYPE_CHECKING, Optional
-from infrahub.message_bus.messages.schema_migration_path import SchemaMigrationPath, SchemaMigrationPathResponse
+from infrahub.message_bus.messages.schema_migration_path import (
+ SchemaMigrationPath,
+ SchemaMigrationPathResponse,
+)
if TYPE_CHECKING:
from infrahub.core.branch import Branch
from infrahub.core.models import SchemaUpdateMigrationInfo
from infrahub.core.schema import MainSchemaTypes
- from infrahub.core.schema_manager import SchemaBranch
+ from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.services import InfrahubServices
diff --git a/backend/infrahub/core/migrations/schema/tasks.py b/backend/infrahub/core/migrations/schema/tasks.py
new file mode 100644
index 0000000000..d67e4ba2aa
--- /dev/null
+++ b/backend/infrahub/core/migrations/schema/tasks.py
@@ -0,0 +1,65 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Optional
+
+from infrahub_sdk.batch import InfrahubBatch
+from prefect import flow
+
+from infrahub.message_bus.messages.schema_migration_path import (
+ SchemaMigrationPathData,
+)
+from infrahub.message_bus.operations.schema.migration import schema_path_migrate
+from infrahub.services import services
+
+from .models import SchemaApplyMigrationData # noqa: TCH001
+
+if TYPE_CHECKING:
+ from infrahub.core.schema import MainSchemaTypes
+
+
+@flow
+async def schema_apply_migrations(message: SchemaApplyMigrationData) -> list[str]:
+ service = services.service
+
+ batch = InfrahubBatch()
+ error_messages: list[str] = []
+
+ if not message.migrations:
+ return error_messages
+
+ for migration in message.migrations:
+ service.log.info(
+ f"Preparing migration for {migration.migration_name!r} ({migration.routing_key})",
+ branch=message.branch.name,
+ )
+
+ new_node_schema: Optional[MainSchemaTypes] = None
+ previous_node_schema: Optional[MainSchemaTypes] = None
+
+ if message.new_schema.has(name=migration.path.schema_kind):
+ new_node_schema = message.new_schema.get(name=migration.path.schema_kind)
+
+ if new_node_schema and new_node_schema.id:
+ previous_node_schema = message.previous_schema.get_by_id(id=new_node_schema.id)
+ else:
+ previous_node_schema = message.previous_schema.get(name=migration.path.schema_kind)
+
+ if not previous_node_schema:
+ raise ValueError(
+ f"Unable to find the previous version of the schema for {migration.path.schema_kind}, in order to run the migration."
+ )
+
+ msg = SchemaMigrationPathData(
+ branch=message.branch,
+ migration_name=migration.migration_name,
+ new_node_schema=new_node_schema,
+ previous_node_schema=previous_node_schema,
+ schema_path=migration.path,
+ )
+
+ batch.add(task=schema_path_migrate, message=msg)
+
+ async for _, result in batch.execute():
+ error_messages.extend(result.errors)
+
+ return error_messages
diff --git a/backend/infrahub/core/migrations/shared.py b/backend/infrahub/core/migrations/shared.py
index d0c721937e..20cf7b3f46 100644
--- a/backend/infrahub/core/migrations/shared.py
+++ b/backend/infrahub/core/migrations/shared.py
@@ -21,7 +21,7 @@
if TYPE_CHECKING:
from infrahub.core.branch import Branch
- from infrahub.core.schema_manager import SchemaBranch
+ from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.timestamp import Timestamp
from infrahub.database import InfrahubDatabase
@@ -141,7 +141,7 @@ class InternalSchemaMigration(BaseModel):
@staticmethod
def get_internal_schema() -> SchemaBranch:
- from infrahub.core.schema_manager import SchemaBranch # pylint: disable=import-outside-toplevel
+ from infrahub.core.schema.schema_branch import SchemaBranch # pylint: disable=import-outside-toplevel
# load the internal schema from
schema = SchemaRoot(**internal_schema)
diff --git a/backend/infrahub/core/models.py b/backend/infrahub/core/models.py
index 81628afd72..0339a40b72 100644
--- a/backend/infrahub/core/models.py
+++ b/backend/infrahub/core/models.py
@@ -17,7 +17,7 @@
if TYPE_CHECKING:
from infrahub.core.schema import MainSchemaTypes
- from infrahub.core.schema_manager import SchemaBranch
+ from infrahub.core.schema.schema_branch import SchemaBranch
class NodeKind(BaseModel):
@@ -409,7 +409,7 @@ def duplicate(self) -> Self:
@staticmethod
def is_list_composed_of_hashable_model(items: list[Any]) -> bool:
- return all((isinstance(item, HashableModel) for item in items))
+ return all(isinstance(item, HashableModel) for item in items)
@staticmethod
def _organize_sub_items(items: list[HashableModel], shared_ids: set[str]) -> dict[tuple[Any], HashableModel]:
@@ -417,7 +417,7 @@ def _organize_sub_items(items: list[HashableModel], shared_ids: set[str]) -> dic
sub_items = {}
for item in items:
if item.id and item.id in shared_ids:
- sub_items[(item.id,)] = item
+ sub_items[item.id,] = item
continue
sub_items[item._sorting_id] = item
diff --git a/backend/infrahub/core/node/__init__.py b/backend/infrahub/core/node/__init__.py
index fe2f423285..85db92eda9 100644
--- a/backend/infrahub/core/node/__init__.py
+++ b/backend/infrahub/core/node/__init__.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from enum import Enum
-from typing import TYPE_CHECKING, Any, Optional, Union
+from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union, overload
from infrahub_sdk import UUIDT
from infrahub_sdk.utils import is_valid_uuid
@@ -27,6 +27,8 @@
from ..attribute import BaseAttribute
+SchemaProtocol = TypeVar("SchemaProtocol")
+
# ---------------------------------------------------------------------------------------
# Type of Nodes
# - Core node, wo/ branch : Branch, MergeRequest, Comment
@@ -43,7 +45,7 @@ class Node(BaseNode, metaclass=BaseNodeMeta):
@classmethod
def __init_subclass_with_meta__( # pylint: disable=arguments-differ
cls, _meta=None, default_filter=None, **options
- ):
+ ) -> None:
if not _meta:
_meta = BaseNodeOptions(cls)
@@ -64,6 +66,9 @@ def get_id(self) -> str:
raise InitializationError("The node has not been saved yet and doesn't have an id")
+ def get_updated_at(self) -> Timestamp | None:
+ return self._updated_at
+
async def get_hfid(self, db: InfrahubDatabase, include_kind: bool = False) -> Optional[list[str]]:
"""Return the Human friendly id of the node."""
if not self._schema.human_friendly_id:
@@ -162,14 +167,34 @@ def __init__(self, schema: Union[NodeSchema, ProfileSchema], branch: Branch, at:
self._attributes: list[str] = []
self._relationships: list[str] = []
+ @overload
@classmethod
async def init(
cls,
schema: Union[NodeSchema, ProfileSchema, str],
db: InfrahubDatabase,
+ branch: Optional[Union[Branch, str]] = ...,
+ at: Optional[Union[Timestamp, str]] = ...,
+ ) -> Self: ...
+
+ @overload
+ @classmethod
+ async def init(
+ cls,
+ schema: type[SchemaProtocol],
+ db: InfrahubDatabase,
+ branch: Optional[Union[Branch, str]] = ...,
+ at: Optional[Union[Timestamp, str]] = ...,
+ ) -> SchemaProtocol: ...
+
+ @classmethod
+ async def init(
+ cls,
+ schema: Union[NodeSchema, ProfileSchema, str, type[SchemaProtocol]],
+ db: InfrahubDatabase,
branch: Optional[Union[Branch, str]] = None,
at: Optional[Union[Timestamp, str]] = None,
- ) -> Self:
+ ) -> Self | SchemaProtocol:
attrs: dict[str, Any] = {}
branch = await registry.get_branch(branch=branch, db=db)
@@ -179,6 +204,8 @@ async def init(
elif isinstance(schema, str):
# TODO need to raise a proper exception for this, right now it will raise a generic ValueError
attrs["schema"] = db.schema.get(name=schema, branch=branch)
+ elif hasattr(schema, "_is_runtime_protocol") and getattr(schema, "_is_runtime_protocol"):
+ attrs["schema"] = db.schema.get(name=schema.__name__, branch=branch)
else:
raise ValueError(f"Invalid schema provided {type(schema)}, expected NodeSchema or ProfileSchema")
diff --git a/backend/infrahub/core/node/base.py b/backend/infrahub/core/node/base.py
index 4f8ca06512..16e443a4fd 100644
--- a/backend/infrahub/core/node/base.py
+++ b/backend/infrahub/core/node/base.py
@@ -14,7 +14,7 @@ class BaseOptions:
def __init__(self, class_type):
self.class_type = class_type
- def freeze(self):
+ def freeze(self) -> None:
self._frozen = True
def __setattr__(self, name, value):
@@ -36,7 +36,7 @@ class BaseNode(SubclassWithMeta):
# return type(class_name, (cls,), {"Meta": options})
@classmethod
- def __init_subclass_with_meta__(cls, name=None, description=None, _meta=None, **_kwargs):
+ def __init_subclass_with_meta__(cls, name=None, description=None, _meta=None, **_kwargs) -> None:
assert "_meta" not in cls.__dict__, "Can't assign meta directly"
if not _meta:
return
diff --git a/backend/infrahub/core/node/constraints/attribute_uniqueness.py b/backend/infrahub/core/node/constraints/attribute_uniqueness.py
index 0f373a4100..661a2234ea 100644
--- a/backend/infrahub/core/node/constraints/attribute_uniqueness.py
+++ b/backend/infrahub/core/node/constraints/attribute_uniqueness.py
@@ -45,7 +45,7 @@ async def check(self, node: Node, at: Optional[Timestamp] = None, filters: Optio
at=at,
)
- if any((n for n in nodes if n.get_id() != node.id)):
+ if any(n for n in nodes if n.get_id() != node.id):
raise ValidationError(
{unique_attr.name: f"An object already exist with this value: {unique_attr.name}: {attr.value}"}
)
diff --git a/backend/infrahub/core/node/constraints/grouped_uniqueness.py b/backend/infrahub/core/node/constraints/grouped_uniqueness.py
index 6e53b7638e..76f6d64c98 100644
--- a/backend/infrahub/core/node/constraints/grouped_uniqueness.py
+++ b/backend/infrahub/core/node/constraints/grouped_uniqueness.py
@@ -105,7 +105,7 @@ def _check_one_constraint_group(
self, schema_attribute_path_values: list[SchemaAttributePathValue], results_index: UniquenessQueryResultsIndex
) -> None:
# constraint cannot be violated if this node is missing any values
- if any((sapv.value is None for sapv in schema_attribute_path_values)):
+ if any(sapv.value is None for sapv in schema_attribute_path_values):
return
matching_node_ids = results_index.get_node_ids_for_value_group(schema_attribute_path_values)
diff --git a/backend/infrahub/core/node/permissions.py b/backend/infrahub/core/node/permissions.py
new file mode 100644
index 0000000000..6223520f22
--- /dev/null
+++ b/backend/infrahub/core/node/permissions.py
@@ -0,0 +1,51 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Optional
+
+from . import Node
+
+if TYPE_CHECKING:
+ from infrahub.database import InfrahubDatabase
+
+
+class CoreGlobalPermission(Node):
+ async def to_graphql(
+ self,
+ db: InfrahubDatabase,
+ fields: Optional[dict] = None,
+ related_node_ids: Optional[set] = None,
+ filter_sensitive: bool = False,
+ ) -> dict:
+ response = await super().to_graphql(
+ db, fields=fields, related_node_ids=related_node_ids, filter_sensitive=filter_sensitive
+ )
+
+ if fields:
+ if "identifier" in fields:
+ response["identifier"] = {"value": f"global:{self.action.value}:{self.decision.value.value}"} # type: ignore[attr-defined]
+
+ return response
+
+
+class CoreObjectPermission(Node):
+ async def to_graphql(
+ self,
+ db: InfrahubDatabase,
+ fields: Optional[dict] = None,
+ related_node_ids: Optional[set] = None,
+ filter_sensitive: bool = False,
+ ) -> dict:
+ response = await super().to_graphql(
+ db, fields=fields, related_node_ids=related_node_ids, filter_sensitive=filter_sensitive
+ )
+
+ if fields:
+ if "identifier" in fields:
+ response["identifier"] = {
+ "value": (
+ f"object:{self.branch.value}:{self.namespace.value}:{self.name.value}:{self.action.value.value}:" # type: ignore[attr-defined]
+ f"{self.decision.value.value}" # type: ignore[attr-defined]
+ )
+ }
+
+ return response
diff --git a/backend/infrahub/core/node/standard.py b/backend/infrahub/core/node/standard.py
index eaf762f852..cb0160b8c9 100644
--- a/backend/infrahub/core/node/standard.py
+++ b/backend/infrahub/core/node/standard.py
@@ -2,7 +2,7 @@
import inspect
from typing import TYPE_CHECKING, Any, Optional, Union, get_args, get_origin
-from uuid import UUID # noqa: TCH003
+from uuid import UUID
import ujson
from infrahub_sdk import UUIDT
diff --git a/backend/infrahub/core/protocols.py b/backend/infrahub/core/protocols.py
index 3138cc6dc8..a49de3ff52 100644
--- a/backend/infrahub/core/protocols.py
+++ b/backend/infrahub/core/protocols.py
@@ -66,6 +66,12 @@ class CoreArtifactTarget(CoreNode):
artifacts: RelationshipManager
+class CoreBasePermission(CoreNode):
+ decision: Enum
+ identifier: StringOptional
+ roles: RelationshipManager
+
+
class CoreCheck(CoreNode):
name: StringOptional
label: StringOptional
@@ -127,6 +133,20 @@ class CoreGroup(CoreNode):
children: RelationshipManager
+class CoreMenu(CoreNode):
+ namespace: String
+ name: String
+ label: StringOptional
+ path: StringOptional
+ description: StringOptional
+ icon: StringOptional
+ protected: Boolean
+ order_weight: Integer
+ section: Enum
+ parent: RelationshipManager
+ children: RelationshipManager
+
+
class CoreProfile(CoreNode):
profile_name: String
profile_priority: IntegerOptional
@@ -194,6 +214,16 @@ class CoreAccount(LineageOwner, LineageSource, CoreGenericAccount):
pass
+class CoreAccountGroup(CoreGroup):
+ roles: RelationshipManager
+
+
+class CoreAccountRole(CoreNode):
+ name: String
+ groups: RelationshipManager
+ permissions: RelationshipManager
+
+
class CoreArtifact(CoreTaskTarget):
name: String
status: Enum
@@ -311,6 +341,11 @@ class CoreGeneratorValidator(CoreValidator):
definition: RelationshipManager
+class CoreGlobalPermission(CoreBasePermission):
+ name: String
+ action: Dropdown
+
+
class CoreGraphQLQuery(CoreNode):
name: String
description: StringOptional
@@ -344,6 +379,10 @@ class CoreIPPrefixPool(CoreResourcePool, LineageSource):
ip_namespace: RelationshipManager
+class CoreMenuItem(CoreMenu):
+ pass
+
+
class CoreNumberPool(CoreResourcePool, LineageSource):
node: String
node_attribute: String
@@ -351,6 +390,13 @@ class CoreNumberPool(CoreResourcePool, LineageSource):
end_range: Integer
+class CoreObjectPermission(CoreBasePermission):
+ branch: String
+ namespace: String
+ name: String
+ action: Enum
+
+
class CoreObjectThread(CoreThread):
object_path: String
diff --git a/backend/infrahub/core/protocols_base.py b/backend/infrahub/core/protocols_base.py
index 31fc37f277..f7a5fb5a90 100644
--- a/backend/infrahub/core/protocols_base.py
+++ b/backend/infrahub/core/protocols_base.py
@@ -7,11 +7,9 @@
if TYPE_CHECKING:
from neo4j import AsyncResult, AsyncSession, AsyncTransaction, Record
-# pylint: disable=redefined-builtin
-
+ from infrahub.core.schema.schema_branch import SchemaBranch
-@runtime_checkable
-class SchemaBranch(Protocol): ...
+# pylint: disable=redefined-builtin
@runtime_checkable
diff --git a/backend/infrahub/core/query/attribute.py b/backend/infrahub/core/query/attribute.py
index f85a508ebc..a949610666 100644
--- a/backend/infrahub/core/query/attribute.py
+++ b/backend/infrahub/core/query/attribute.py
@@ -46,7 +46,7 @@ class AttributeUpdateValueQuery(AttributeQuery):
raise_error_if_empty: bool = True
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
at = self.at or self.attr.at
self.params["attr_uuid"] = self.attr.id
@@ -95,7 +95,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
at = self.at or self.attr.at
self.params["attr_uuid"] = self.attr.id
@@ -132,7 +132,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
at = self.at or self.attr.at
self.params["attr_uuid"] = self.attr.id
@@ -161,7 +161,7 @@ class AttributeGetQuery(AttributeQuery):
name = "attribute_get"
type: QueryType = QueryType.READ
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["attr_uuid"] = self.attr.id
self.params["node_uuid"] = self.attr.node.id
diff --git a/backend/infrahub/core/query/diff.py b/backend/infrahub/core/query/diff.py
index ee991039d6..5d95ead3f1 100644
--- a/backend/infrahub/core/query/diff.py
+++ b/backend/infrahub/core/query/diff.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Optional, Union
+from typing import TYPE_CHECKING, Any, Optional, Union
from infrahub.core.constants import BranchSupportType
from infrahub.core.query import Query, QueryResult, QueryType, sort_results_by_time
@@ -66,7 +66,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
# TODO need to improve the query to capture an object that has been deleted into the branch
# TODO probably also need to consider a node what was merged already
@@ -132,7 +132,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
# TODO need to improve the query to capture an object that has been deleted into the branch
rels_filters, rels_params = self.branch.get_query_filter_relationships_diff(
@@ -195,7 +195,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
where_clause = ""
if self.namespaces_include:
where_clause += "(src.namespace IN $namespaces_include OR dst.namespace IN $namespaces_include) AND "
@@ -257,7 +257,7 @@ class DiffRelationshipPropertyQuery(DiffQuery):
name: str = "diff_relationship_property"
type: QueryType = QueryType.READ
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
rels_filter, rels_params = self.branch.get_query_filter_relationships_range(
rel_labels=["r"], start_time=self.diff_from, end_time=self.diff_to
)
@@ -307,7 +307,7 @@ def __init__(self, ids: list[str], diff_from: str, diff_to: str, account=None, *
super().__init__(order_by=["a.name"], **kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ids"] = self.ids
rels_filter, rels_params = self.branch.get_query_filter_relationships_range(
@@ -358,7 +358,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ids"] = self.ids
rels_filter, rels_params = self.branch.get_query_filter_relationships(
@@ -412,7 +412,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ids"] = self.ids
rels_filter, rels_params = self.branch.get_query_filter_relationships_range(
@@ -464,7 +464,7 @@ def __init__(
self.diff_to = diff_to
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params = {
"from_time": self.diff_from.to_string(),
"to_time": self.diff_to.to_string(),
@@ -511,8 +511,7 @@ def __init__(
branch_support: list[BranchSupportType] | None = None,
current_node_field_specifiers: list[tuple[str, str]] | None = None,
new_node_field_specifiers: list[tuple[str, str]] | None = None,
- *args,
- **kwargs,
+ **kwargs: Any,
):
self.base_branch = base_branch
self.diff_branch_from_time = diff_branch_from_time
@@ -520,9 +519,9 @@ def __init__(
self.current_node_field_specifiers = current_node_field_specifiers
self.new_node_field_specifiers = new_node_field_specifiers
- super().__init__(*args, **kwargs)
+ super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None:
from_str = self.diff_from.to_string()
self.params.update(
{
diff --git a/backend/infrahub/core/query/ipam.py b/backend/infrahub/core/query/ipam.py
index 1c69b61c85..ff73615f4b 100644
--- a/backend/infrahub/core/query/ipam.py
+++ b/backend/infrahub/core/query/ipam.py
@@ -60,7 +60,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ns_id"] = self.namespace_id
prefix_bin = convert_ip_to_binary_str(self.obj)[: self.obj.prefixlen]
@@ -124,7 +124,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs):
self.return_labels = ["prefixes_to_check[0] as pfx", "prefixes_to_check[1] as av"]
self.order_by = ["av.binary_address"]
- def get_subnets(self):
+ def get_subnets(self) -> list[IPPrefixData]:
"""Return a list of all subnets fitting in the prefix."""
subnets: list[IPPrefixData] = []
@@ -151,7 +151,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ns_id"] = self.namespace_id
prefix_bin = convert_ip_to_binary_str(self.obj)[: self.obj.prefixlen]
@@ -197,7 +197,7 @@ async def query_init(self, db: InfrahubDatabase, **kwargs):
self.return_labels = ["addr", "av"]
self.order_by = ["av.binary_address"]
- def get_addresses(self):
+ def get_addresses(self) -> list[IPAddressData]:
"""Return a list of all addresses fitting in the prefix."""
addresses: list[IPAddressData] = []
@@ -249,7 +249,7 @@ def __init__(self, ip_prefixes: list[str], **kwargs):
self.ip_prefixes = ip_prefixes
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ids"] = [p.get_id() for p in self.ip_prefixes]
self.params["time_at"] = self.at.to_string()
@@ -323,7 +323,7 @@ def __init__(
self.namespace_id = _get_namespace_id(namespace)
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
self.params.update(branch_params)
self.params["namespace_kind"] = InfrahubKind.IPNAMESPACE
diff --git a/backend/infrahub/core/query/node.py b/backend/infrahub/core/query/node.py
index 3b607f4a5c..a990458f1c 100644
--- a/backend/infrahub/core/query/node.py
+++ b/backend/infrahub/core/query/node.py
@@ -122,7 +122,7 @@ class NodeCreateAllQuery(NodeQuery):
raise_error_if_empty: bool = True
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
at = self.at or self.node._at
self.params["uuid"] = self.node.id
self.params["branch"] = self.branch.name
@@ -355,7 +355,7 @@ class NodeDeleteQuery(NodeQuery):
raise_error_if_empty: bool = True
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["uuid"] = self.node_id
self.params["branch"] = self.branch.name
self.params["branch_level"] = self.branch.hierarchy_level
@@ -385,7 +385,7 @@ def __init__(
self.node_id = node_id
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["uuid"] = self.node_id
query = """
@@ -424,7 +424,7 @@ def __init__(
super().__init__(order_by=["n.uuid", "a.name"], **kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ids"] = self.ids
branch_filter, branch_params = self.branch.get_query_filter_path(
@@ -563,7 +563,7 @@ def __init__(self, ids: list[str], **kwargs):
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["ids"] = self.ids
rels_filter, rels_params = self.branch.get_query_filter_path(at=self.at, branch_agnostic=self.branch_agnostic)
@@ -1108,7 +1108,7 @@ def _get_field_requirements(self) -> list[FieldAttributeRequirement]:
continue
field = self.schema.get_field(field_name, raise_on_error=False)
for field_attr_name, field_attr_value in attr_filters.items():
- field_requirements_map[(field_name, field_attr_name)] = FieldAttributeRequirement(
+ field_requirements_map[field_name, field_attr_name] = FieldAttributeRequirement(
field_name=field_name,
field=field,
field_attr_name=field_attr_name,
@@ -1138,7 +1138,7 @@ def _get_field_requirements(self) -> list[FieldAttributeRequirement]:
),
)
field_req.types.append(FieldAttributeRequirementType.ORDER)
- field_requirements_map[(order_by_field_name, order_by_attr_property_name)] = field_req
+ field_requirements_map[order_by_field_name, order_by_attr_property_name] = field_req
index += 1
return list(field_requirements_map.values())
diff --git a/backend/infrahub/core/query/relationship.py b/backend/infrahub/core/query/relationship.py
index b83f43a1a1..daad6eeeeb 100644
--- a/backend/infrahub/core/query/relationship.py
+++ b/backend/infrahub/core/query/relationship.py
@@ -37,7 +37,7 @@ class RelData:
status: str
@classmethod
- def from_db(cls, obj: Neo4jRelationship):
+ def from_db(cls, obj: Neo4jRelationship) -> RelData:
return cls(db_id=obj.element_id, branch=obj.get("branch"), type=obj.type, status=obj.get("status"))
@@ -204,7 +204,7 @@ def __init__(
super().__init__(destination=destination, destination_id=destination_id, **kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["source_id"] = self.source_id
self.params["destination_id"] = self.destination_id
self.params["name"] = self.schema.identifier
@@ -249,22 +249,22 @@ async def query_init(self, db: InfrahubDatabase, **kwargs):
self.return_labels = ["s", "d", "rl", "r1", "r2", "r3", "r4"]
self.query_add_all_node_property_create()
- def query_add_all_node_property_match(self):
+ def query_add_all_node_property_match(self) -> None:
for prop_name in self.rel._node_properties:
if hasattr(self.rel, f"{prop_name}_id") and getattr(self.rel, f"{prop_name}_id"):
self.query_add_node_property_match(name=prop_name)
- def query_add_node_property_match(self, name: str):
+ def query_add_node_property_match(self, name: str) -> None:
self.add_to_query("MATCH (%s { uuid: $prop_%s_id })" % (name, name))
self.params[f"prop_{name}_id"] = getattr(self.rel, f"{name}_id")
self.return_labels.append(name)
- def query_add_all_node_property_create(self):
+ def query_add_all_node_property_create(self) -> None:
for prop_name in self.rel._node_properties:
if hasattr(self.rel, f"{prop_name}_id") and getattr(self.rel, f"{prop_name}_id"):
self.query_add_node_property_create(name=prop_name)
- def query_add_node_property_create(self, name: str):
+ def query_add_node_property_create(self, name: str) -> None:
query = """
CREATE (rl)-[:HAS_%s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(%s)
""" % (
@@ -290,7 +290,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["rel_node_id"] = self.data.rel_node_id
self.params["branch"] = self.branch.name
self.params["branch_level"] = self.branch.hierarchy_level
@@ -307,32 +307,32 @@ async def query_init(self, db: InfrahubDatabase, **kwargs):
self.query_add_all_flag_property_create()
self.query_add_all_node_property_create()
- def query_add_all_flag_property_merge(self):
+ def query_add_all_flag_property_merge(self) -> None:
for prop_name in self.rel._flag_properties:
if prop_name in self.properties_to_update:
self.query_add_flag_property_merge(name=prop_name)
- def query_add_flag_property_merge(self, name: str):
+ def query_add_flag_property_merge(self, name: str) -> None:
self.add_to_query("MERGE (prop_%s:Boolean { value: $prop_%s })" % (name, name))
self.params[f"prop_{name}"] = getattr(self.rel, name)
self.return_labels.append(f"prop_{name}")
- def query_add_all_node_property_merge(self):
+ def query_add_all_node_property_merge(self) -> None:
for prop_name in self.rel._node_properties:
if prop_name in self.properties_to_update:
self.query_add_node_property_merge(name=prop_name)
- def query_add_node_property_merge(self, name: str):
+ def query_add_node_property_merge(self, name: str) -> None:
self.add_to_query("MERGE (prop_%s:Node { uuid: $prop_%s })" % (name, name))
self.params[f"prop_{name}"] = getattr(self.rel, f"{name}_id")
self.return_labels.append(f"prop_{name}")
- def query_add_all_flag_property_create(self):
+ def query_add_all_flag_property_create(self) -> None:
for prop_name in self.rel._flag_properties:
if prop_name in self.properties_to_update:
self.query_add_flag_property_create(name=prop_name)
- def query_add_flag_property_create(self, name: str):
+ def query_add_flag_property_create(self, name: str) -> None:
query = """
CREATE (rl)-[:%s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(prop_%s)
""" % (
@@ -341,12 +341,12 @@ def query_add_flag_property_create(self, name: str):
)
self.add_to_query(query)
- def query_add_all_node_property_create(self):
+ def query_add_all_node_property_create(self) -> None:
for prop_name in self.rel._node_properties:
if prop_name in self.properties_to_update:
self.query_add_node_property_create(name=prop_name)
- def query_add_node_property_create(self, name: str):
+ def query_add_node_property_create(self, name: str) -> None:
query = """
CREATE (rl)-[:%s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(prop_%s)
""" % (
@@ -369,7 +369,7 @@ def __init__(
self.data = data
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["source_id"] = self.source_id
self.params["destination_id"] = self.data.peer_id
self.params["rel_node_id"] = self.data.rel_node_id
@@ -434,7 +434,7 @@ def __init__(self, **kwargs):
if inspect.isclass(self.rel):
raise TypeError("An instance of Relationship must be provided to RelationshipDeleteQuery")
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["source_id"] = self.source_id
self.params["destination_id"] = self.destination_id
self.params["rel_id"] = self.rel.id
@@ -533,7 +533,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs): # pylint: disable=too-many-statements
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # pylint: disable=too-many-statements
branch_filter, branch_params = self.branch.get_query_filter_path(
at=self.at, branch_agnostic=self.branch_agnostic
)
@@ -733,7 +733,7 @@ class RelationshipGetQuery(RelationshipQuery):
type: QueryType = QueryType.READ
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
self.params["source_id"] = self.source_id
self.params["destination_id"] = self.destination_id
self.params["name"] = self.schema.identifier
@@ -860,7 +860,7 @@ def __init__(
super().__init__(**kwargs)
- async def query_init(self, db: InfrahubDatabase, **kwargs):
+ async def query_init(self, db: InfrahubDatabase, **kwargs) -> None:
branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
self.params.update(branch_params)
diff --git a/backend/infrahub/core/registry.py b/backend/infrahub/core/registry.py
index 774e9af466..8fd3b608f9 100644
--- a/backend/infrahub/core/registry.py
+++ b/backend/infrahub/core/registry.py
@@ -15,10 +15,11 @@
from infrahub.core.branch import Branch
from infrahub.core.manager import NodeManager
from infrahub.core.schema import MainSchemaTypes, NodeSchema
- from infrahub.core.schema_manager import SchemaManager
+ from infrahub.core.schema.manager import SchemaManager
from infrahub.database import InfrahubDatabase
from infrahub.graphql.mutations.attribute import BaseAttributeCreate, BaseAttributeUpdate
from infrahub.graphql.types import InfrahubObject
+ from infrahub.permissions import PermissionBackend
from infrahub.storage import InfrahubObjectStorage
from infrahub.types import InfrahubDataType
@@ -34,7 +35,7 @@ class Registry:
_default_branch: Optional[str] = None
_default_ipnamespace: Optional[str] = None
_schema: Optional[SchemaManager] = None
- default_graphql_type: dict[str, InfrahubObject] = field(default_factory=dict)
+ default_graphql_type: dict[str, InfrahubObject | type[BaseAttribute]] = field(default_factory=dict)
graphql_type: dict = field(default_factory=lambda: defaultdict(dict))
data_type: dict[str, type[InfrahubDataType]] = field(default_factory=dict)
input_type: dict[str, Union[BaseAttributeCreate, BaseAttributeUpdate]] = field(default_factory=dict)
@@ -45,6 +46,7 @@ class Registry:
_branch_object: Optional[type[Branch]] = None
_manager: Optional[type[NodeManager]] = None
_storage: Optional[InfrahubObjectStorage] = None
+ permission_backends: list[PermissionBackend] = field(default_factory=list)
@property
def branch_object(self) -> type[Branch]:
diff --git a/backend/infrahub/core/relationship/__init__.py b/backend/infrahub/core/relationship/__init__.py
index f2e9663a75..c14c2c2381 100644
--- a/backend/infrahub/core/relationship/__init__.py
+++ b/backend/infrahub/core/relationship/__init__.py
@@ -1,3 +1,3 @@
from .model import Relationship, RelationshipCreateData, RelationshipManager
-__all__ = ["Relationship", "RelationshipManager", "RelationshipCreateData"]
+__all__ = ["Relationship", "RelationshipCreateData", "RelationshipManager"]
diff --git a/backend/infrahub/core/relationship/model.py b/backend/infrahub/core/relationship/model.py
index 93c7aaed75..b6d63df66c 100644
--- a/backend/infrahub/core/relationship/model.py
+++ b/backend/infrahub/core/relationship/model.py
@@ -985,7 +985,7 @@ async def update( # pylint: disable=too-many-branches
self._relationships.append(previous_relationships[str(item_id)])
continue
- if isinstance(item, type(None)):
+ if item is None:
if previous_relationships:
for rel in previous_relationships.values():
await rel.delete(db=db)
diff --git a/backend/infrahub/core/schema/__init__.py b/backend/infrahub/core/schema/__init__.py
index 5428791b29..ee64f90510 100644
--- a/backend/infrahub/core/schema/__init__.py
+++ b/backend/infrahub/core/schema/__init__.py
@@ -7,13 +7,13 @@
from infrahub.core.constants import RESTRICTED_NAMESPACES
from infrahub.core.models import HashableModel
+from infrahub.exceptions import SchemaNotFoundError
from .attribute_schema import AttributeSchema
from .basenode_schema import AttributePathParsingError, BaseNodeSchema, SchemaAttributePath, SchemaAttributePathValue
from .definitions.core import core_models
from .definitions.internal import internal
from .dropdown import DropdownChoice
-from .filter import FilterSchema
from .generic_schema import GenericSchema
from .node_schema import NodeSchema
from .profile_schema import ProfileSchema
@@ -58,6 +58,15 @@ def has_schema(cls, values: dict[str, Any], name: str) -> bool:
return True
+ def get(self, name: str) -> Union[NodeSchema, GenericSchema]:
+ """Check if a schema exist locally as a node or as a generic."""
+
+ for item in self.nodes + self.generics:
+ if item.kind == name:
+ return item
+
+ raise SchemaNotFoundError(branch_name="undefined", identifier=name)
+
def validate_namespaces(self) -> list[str]:
models = self.nodes + self.generics
errors: list[str] = []
@@ -81,19 +90,18 @@ def generate_uuid(self) -> None:
internal_schema = internal.to_dict()
__all__ = [
- "core_models",
- "internal_schema",
"AttributePathParsingError",
"AttributeSchema",
"BaseNodeSchema",
"DropdownChoice",
- "FilterSchema",
- "NodeSchema",
"GenericSchema",
+ "MainSchemaTypes",
+ "NodeSchema",
"ProfileSchema",
"RelationshipSchema",
"SchemaAttributePath",
"SchemaAttributePathValue",
"SchemaRoot",
- "MainSchemaTypes",
+ "core_models",
+ "internal_schema",
]
diff --git a/backend/infrahub/core/schema/basenode_schema.py b/backend/infrahub/core/schema/basenode_schema.py
index b5fe047bd5..a63fb792ee 100644
--- a/backend/infrahub/core/schema/basenode_schema.py
+++ b/backend/infrahub/core/schema/basenode_schema.py
@@ -12,16 +12,15 @@
from infrahub.core.constants import RelationshipKind
from infrahub.core.models import HashableModelDiff
-from .attribute_schema import AttributeSchema # noqa: TCH001
-from .filter import FilterSchema # noqa: TCH001
+from .attribute_schema import AttributeSchema
from .generated.base_node_schema import GeneratedBaseNodeSchema
-from .relationship_schema import RelationshipSchema # noqa: TCH001
+from .relationship_schema import RelationshipSchema
if TYPE_CHECKING:
from typing_extensions import Self
from infrahub.core.schema import GenericSchema, NodeSchema
- from infrahub.core.schema_manager import SchemaBranch
+ from infrahub.core.schema.schema_branch import SchemaBranch
# pylint: disable=redefined-builtin
@@ -30,7 +29,7 @@
class BaseNodeSchema(GeneratedBaseNodeSchema): # pylint: disable=too-many-public-methods
- _exclude_from_hash: list[str] = ["attributes", "relationships", "filters"]
+ _exclude_from_hash: list[str] = ["attributes", "relationships"]
_sort_by: list[str] = ["namespace", "name"]
@property
@@ -77,9 +76,6 @@ def get_hash(self, display_values: bool = False) -> str:
for rel_name in sorted(self.relationship_names):
md5hash.update(self.get_relationship(name=rel_name).get_hash(display_values=display_values).encode())
- for filter_name in sorted(self.filter_names):
- md5hash.update(self.get_filter(name=filter_name).get_hash(display_values=display_values).encode())
-
return md5hash.hexdigest()
def diff(self, other: Self) -> HashableModelDiff:
@@ -114,7 +110,7 @@ def _diff_element(
other: Self,
get_func: Callable,
get_map_func: Callable,
- obj_type: type[Union[AttributeSchema, RelationshipSchema, FilterSchema]],
+ obj_type: type[Union[AttributeSchema, RelationshipSchema]],
) -> HashableModelDiff:
"""The goal of this function is to reduce the amount of code duplicated between Attribute and Relationship to calculate a diff
The logic is the same for both, except that the functions we are using to access these objects are differents
@@ -224,22 +220,6 @@ def get_relationship_by_id(self, id: str) -> RelationshipSchema:
raise ValueError(f"Unable to find the relationship with the ID: {id}")
- @overload
- def get_filter(self, name: str, raise_on_error: Literal[True] = True) -> FilterSchema: ...
-
- @overload
- def get_filter(self, name: str, raise_on_error: Literal[False] = False) -> Optional[FilterSchema]: ...
-
- def get_filter(self, name: str, raise_on_error: bool = True) -> Optional[FilterSchema]:
- for item in self.filters:
- if item.name == name:
- return item
-
- if not raise_on_error:
- return None
-
- raise ValueError(f"Unable to find the filter {name}")
-
def get_relationship_or_none(self, name: str) -> Optional[RelationshipSchema]:
for item in self.relationships:
if item.name == name:
@@ -295,12 +275,6 @@ def has_parent_relationship(self) -> bool:
return True
return False
- def get_filter_name_id_map(self) -> dict[str, str]:
- name_id_map = {}
- for filter in self.filters:
- name_id_map[filter.name] = filter.id
- return name_id_map
-
@property
def valid_input_names(self) -> list[str]:
return self.attribute_names + self.relationship_names + NODE_METADATA_ATTRIBUTES
@@ -317,10 +291,6 @@ def attribute_names(self) -> list[str]:
def relationship_names(self) -> list[str]:
return [item.name for item in self.relationships]
- @property
- def filter_names(self) -> list[str]:
- return [item.name for item in self.filters]
-
@property
def mandatory_input_names(self) -> list[str]:
return self.mandatory_attribute_names + self.mandatory_relationship_names
diff --git a/backend/infrahub/core/schema/constants.py b/backend/infrahub/core/schema/constants.py
new file mode 100644
index 0000000000..76c4ee8950
--- /dev/null
+++ b/backend/infrahub/core/schema/constants.py
@@ -0,0 +1,14 @@
+from pydantic import BaseModel
+
+from . import internal_schema
+
+INTERNAL_SCHEMA_NODE_KINDS = [node["namespace"] + node["name"] for node in internal_schema["nodes"]]
+
+SUPPORTED_SCHEMA_EXTENSION_TYPE = ["NodeExtensionSchema"]
+
+IGNORE_FOR_NODE = {"id", "state", "filters", "relationships", "attributes"}
+
+
+class SchemaNamespace(BaseModel):
+ name: str
+ user_editable: bool
diff --git a/backend/infrahub/core/schema/definitions/core.py b/backend/infrahub/core/schema/definitions/core.py
index 91502d2759..c839c1ccf6 100644
--- a/backend/infrahub/core/schema/definitions/core.py
+++ b/backend/infrahub/core/schema/definitions/core.py
@@ -3,6 +3,7 @@
from infrahub.core.constants import (
DEFAULT_KIND_MAX_LENGTH,
DEFAULT_KIND_MIN_LENGTH,
+ NAMESPACE_REGEX,
AccountRole,
AccountStatus,
AccountType,
@@ -12,7 +13,10 @@
BranchSupportType,
ContentType,
GeneratorInstanceStatus,
+ GlobalPermissions,
InfrahubKind,
+ PermissionAction,
+ PermissionDecision,
ProposedChangeState,
RelationshipDeleteBehavior,
RepositoryInternalStatus,
@@ -53,6 +57,44 @@
],
}
+# -----------------------------------------------
+# Menu Items
+# -----------------------------------------------
+generic_menu_item: dict[str, Any] = {
+ "name": "Menu",
+ "namespace": "Core",
+ "include_in_menu": False,
+ "description": "Base node for the menu",
+ "label": "Menu Item",
+ "hierarchical": True,
+ "uniqueness_constraints": [["namespace__value", "name__value"]],
+ "attributes": [
+ {"name": "namespace", "kind": "Text", "regex": NAMESPACE_REGEX, "order_weight": 1000},
+ {"name": "name", "kind": "Text", "order_weight": 1000},
+ {"name": "label", "kind": "Text", "optional": True, "order_weight": 2000},
+ {"name": "path", "kind": "Text", "optional": True, "order_weight": 2500},
+ {"name": "description", "kind": "Text", "optional": True, "order_weight": 3000},
+ {"name": "icon", "kind": "Text", "optional": True, "order_weight": 4000},
+ {"name": "protected", "kind": "Boolean", "default_value": False, "read_only": True, "order_weight": 5000},
+ {"name": "order_weight", "kind": "Number", "default_value": 2000, "order_weight": 6000},
+ {
+ "name": "section",
+ "kind": "Text",
+ "enum": ["object", "internal"],
+ "default_value": "object",
+ "order_weight": 7000,
+ },
+ ],
+}
+
+menu_item: dict[str, Any] = {
+ "name": "MenuItem",
+ "namespace": "Core",
+ "include_in_menu": False,
+ "description": "Menu Item",
+ "label": "Menu Item",
+ "inherit_from": ["CoreMenu"],
+}
core_models: dict[str, Any] = {
"generics": [
@@ -877,7 +919,42 @@
},
],
"relationships": [
- {"name": "tokens", "peer": InfrahubKind.ACCOUNTTOKEN, "optional": True, "cardinality": "many"},
+ {"name": "tokens", "peer": InfrahubKind.ACCOUNTTOKEN, "optional": True, "cardinality": "many"}
+ ],
+ },
+ {
+ "name": "BasePermission",
+ "namespace": "Core",
+ "description": "A permission grants right to an account",
+ "label": "Base permission",
+ "icon": "mdi:user-key",
+ "include_in_menu": False,
+ "generate_profile": False,
+ "attributes": [
+ {
+ "name": "decision",
+ "kind": "Text",
+ "enum": PermissionDecision.available_types(),
+ "default_value": PermissionDecision.ALLOW.value,
+ "order_weight": 5000,
+ },
+ {
+ "name": "identifier",
+ "kind": "Text",
+ "read_only": True,
+ "optional": True,
+ "allow_override": AllowOverrideType.NONE,
+ },
+ ],
+ "relationships": [
+ {
+ "name": "roles",
+ "peer": InfrahubKind.ACCOUNTROLE,
+ "optional": True,
+ "identifier": "role__permissions",
+ "cardinality": "many",
+ "kind": "Attribute",
+ }
],
},
{
@@ -900,8 +977,10 @@
{"name": "description", "kind": "Text", "optional": True, "order_weight": 3000},
],
},
+ generic_menu_item,
],
"nodes": [
+ menu_item,
{
"name": "StandardGroup",
"namespace": "Core",
@@ -2080,5 +2159,105 @@
},
],
},
+ {
+ "name": "GlobalPermission",
+ "namespace": "Core",
+ "description": "A permission that grants global rights to perform actions in Infrahub",
+ "label": "Global permission",
+ "include_in_menu": False,
+ "order_by": ["name__value", "action__value"],
+ "display_labels": ["name__value"],
+ "generate_profile": False,
+ "inherit_from": [InfrahubKind.BASEPERMISSION],
+ "branch": BranchSupportType.AGNOSTIC.value,
+ "attributes": [
+ {"name": "name", "kind": "Text", "unique": True, "order_weight": 1000},
+ {
+ "name": "action",
+ "kind": "Dropdown",
+ "choices": [{"name": permission.value} for permission in GlobalPermissions],
+ "order_weight": 2000,
+ },
+ ],
+ },
+ {
+ "name": "ObjectPermission",
+ "namespace": "Core",
+ "description": "A permission that grants rights to perform actions on objects",
+ "label": "Object permission",
+ "include_in_menu": False,
+ "order_by": ["branch__value", "namespace__value", "name__value", "action__value", "decision__value"],
+ "display_labels": ["branch__value", "namespace__value", "name__value", "action__value", "decision__value"],
+ "uniqueness_constraints": [
+ ["branch__value", "namespace__value", "name__value", "action__value", "decision__value"]
+ ],
+ "generate_profile": False,
+ "inherit_from": [InfrahubKind.BASEPERMISSION],
+ "attributes": [
+ {"name": "branch", "kind": "Text", "order_weight": 1000},
+ {"name": "namespace", "kind": "Text", "order_weight": 2000},
+ {"name": "name", "kind": "Text", "order_weight": 3000},
+ {
+ "name": "action",
+ "kind": "Text",
+ "enum": PermissionAction.available_types(),
+ "default_value": PermissionAction.ANY.value,
+ "order_weight": 4000,
+ },
+ ],
+ },
+ {
+ "name": "AccountRole",
+ "namespace": "Core",
+ "description": "A role defines a set of permissions to grant to a group of accounts",
+ "label": "Account role",
+ "icon": "mdi:user-badge",
+ "include_in_menu": False,
+ "order_by": ["name__value"],
+ "display_labels": ["name__value"],
+ "generate_profile": False,
+ "attributes": [{"name": "name", "kind": "Text", "unique": True}],
+ "relationships": [
+ {
+ "name": "groups",
+ "peer": InfrahubKind.ACCOUNTGROUP,
+ "optional": True,
+ "identifier": "role__accountgroups",
+ "cardinality": "many",
+ "kind": "Attribute",
+ },
+ {
+ "name": "permissions",
+ "peer": InfrahubKind.BASEPERMISSION,
+ "optional": True,
+ "identifier": "role__permissions",
+ "cardinality": "many",
+ "kind": "Attribute",
+ },
+ ],
+ },
+ {
+ "name": "AccountGroup",
+ "namespace": "Core",
+ "description": "A group of users to manage common permissions",
+ "label": "Account group",
+ "icon": "mdi:account-group",
+ "include_in_menu": False,
+ "order_by": ["name__value"],
+ "display_labels": ["name__value"],
+ "generate_profile": False,
+ "inherit_from": [InfrahubKind.GENERICGROUP],
+ "branch": BranchSupportType.AGNOSTIC.value,
+ "relationships": [
+ {
+ "name": "roles",
+ "peer": InfrahubKind.ACCOUNTROLE,
+ "optional": True,
+ "identifier": "role__accountgroups",
+ "cardinality": "many",
+ "kind": "Attribute",
+ }
+ ],
+ },
],
}
diff --git a/backend/infrahub/core/schema/definitions/internal.py b/backend/infrahub/core/schema/definitions/internal.py
index e6c80564dc..f7c065fe15 100644
--- a/backend/infrahub/core/schema/definitions/internal.py
+++ b/backend/infrahub/core/schema/definitions/internal.py
@@ -30,10 +30,9 @@
RelationshipKind,
UpdateSupport,
)
-from infrahub.core.schema.attribute_schema import AttributeSchema # noqa: TCH001
+from infrahub.core.schema.attribute_schema import AttributeSchema
from infrahub.core.schema.dropdown import DropdownChoice
-from infrahub.core.schema.filter import FilterSchema
-from infrahub.core.schema.relationship_schema import RelationshipSchema # noqa: TCH001
+from infrahub.core.schema.relationship_schema import RelationshipSchema
from infrahub.types import ATTRIBUTE_KIND_LABELS
@@ -181,7 +180,7 @@ def to_dict(self) -> dict[str, Any]:
"attributes": [
attribute.to_dict()
for attribute in self.attributes
- if attribute.name not in ["id", "filters", "attributes", "relationships"]
+ if attribute.name not in ["id", "attributes", "relationships"]
],
"relationships": [relationship.to_dict() for relationship in self.relationships],
"display_labels": self.display_labels,
@@ -346,15 +345,6 @@ def to_dict(self) -> dict[str, Any]:
optional=True,
extra={"update": UpdateSupport.NOT_APPLICABLE},
),
- SchemaAttribute(
- name="filters",
- kind="List",
- internal_kind=FilterSchema,
- description="Node filters",
- default_factory="list",
- optional=True,
- extra={"update": UpdateSupport.NOT_APPLICABLE},
- ),
SchemaAttribute(
name="attributes",
kind="List",
@@ -776,15 +766,6 @@ def to_dict(self) -> dict[str, Any]:
optional=True,
extra={"update": UpdateSupport.NOT_APPLICABLE},
),
- SchemaAttribute(
- name="filters",
- kind="List",
- internal_kind=FilterSchema,
- description="Relationship filters",
- default_factory="list",
- optional=True,
- extra={"update": UpdateSupport.NOT_APPLICABLE},
- ),
SchemaAttribute(
name="on_delete",
kind="Text",
diff --git a/backend/infrahub/core/schema/filter.py b/backend/infrahub/core/schema/filter.py
deleted file mode 100644
index 0b56d3caa2..0000000000
--- a/backend/infrahub/core/schema/filter.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from typing import Optional
-
-from infrahub.core.constants import FilterSchemaKind
-from infrahub.core.models import HashableModel
-
-
-class FilterSchema(HashableModel):
- name: str
- kind: FilterSchemaKind
- enum: Optional[list] = None
- object_kind: Optional[str] = None
- description: Optional[str] = None
-
- _sort_by: list[str] = ["name"]
diff --git a/backend/infrahub/core/schema/generated/base_node_schema.py b/backend/infrahub/core/schema/generated/base_node_schema.py
index c9691af782..91f86ac8a6 100644
--- a/backend/infrahub/core/schema/generated/base_node_schema.py
+++ b/backend/infrahub/core/schema/generated/base_node_schema.py
@@ -9,7 +9,6 @@
from infrahub.core.constants import BranchSupportType, HashableModelState
from infrahub.core.models import HashableModel
from infrahub.core.schema.attribute_schema import AttributeSchema # noqa: TCH001
-from infrahub.core.schema.filter import FilterSchema # noqa: TCH001
from infrahub.core.schema.relationship_schema import RelationshipSchema # noqa: TCH001
@@ -101,9 +100,6 @@ class GeneratedBaseNodeSchema(HashableModel):
description="Expected state of the node/generic after loading the schema",
json_schema_extra={"update": "not_applicable"},
)
- filters: list[FilterSchema] = Field(
- default_factory=list, description="Node filters", json_schema_extra={"update": "not_applicable"}
- )
attributes: list[AttributeSchema] = Field(
default_factory=list, description="Node attributes", json_schema_extra={"update": "not_applicable"}
)
diff --git a/backend/infrahub/core/schema/generated/relationship_schema.py b/backend/infrahub/core/schema/generated/relationship_schema.py
index 53d45f050c..c36e2f01ab 100644
--- a/backend/infrahub/core/schema/generated/relationship_schema.py
+++ b/backend/infrahub/core/schema/generated/relationship_schema.py
@@ -15,10 +15,7 @@
RelationshipDirection,
RelationshipKind,
)
-
-# noqa: TCH001
from infrahub.core.models import HashableModel
-from infrahub.core.schema.filter import FilterSchema # noqa: TCH001
class GeneratedRelationshipSchema(HashableModel):
@@ -113,9 +110,6 @@ class GeneratedRelationshipSchema(HashableModel):
description="Expected state of the relationship after loading the schema",
json_schema_extra={"update": "not_applicable"},
)
- filters: list[FilterSchema] = Field(
- default_factory=list, description="Relationship filters", json_schema_extra={"update": "not_applicable"}
- )
on_delete: Optional[RelationshipDeleteBehavior] = Field(
default=None,
description="Default is no-action. If cascade, related node(s) are deleted when this node is deleted.",
diff --git a/backend/infrahub/core/schema/manager.py b/backend/infrahub/core/schema/manager.py
new file mode 100644
index 0000000000..ade133a361
--- /dev/null
+++ b/backend/infrahub/core/schema/manager.py
@@ -0,0 +1,673 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Optional, Union
+
+from infrahub import lock
+from infrahub.core.constants import (
+ InfrahubKind,
+)
+from infrahub.core.manager import NodeManager
+from infrahub.core.models import (
+ HashableModelDiff,
+ SchemaBranchDiff,
+ SchemaDiff,
+)
+from infrahub.core.node import Node
+from infrahub.core.registry import registry
+from infrahub.core.schema import (
+ AttributeSchema,
+ GenericSchema,
+ MainSchemaTypes,
+ NodeSchema,
+ RelationshipSchema,
+ SchemaRoot,
+)
+from infrahub.core.utils import parse_node_kind
+from infrahub.exceptions import SchemaNotFoundError
+from infrahub.log import get_logger
+
+from .constants import IGNORE_FOR_NODE
+from .schema_branch import SchemaBranch
+
+log = get_logger()
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.timestamp import Timestamp
+ from infrahub.database import InfrahubDatabase
+
+
+# pylint: disable=too-many-public-methods
+class SchemaManager(NodeManager):
+ def __init__(self) -> None:
+ self._cache: dict[int, Any] = {}
+ self._branches: dict[str, SchemaBranch] = {}
+
+ def _get_from_cache(self, key: int) -> Any:
+ return self._cache[key]
+
+ def set(self, name: str, schema: Union[NodeSchema, GenericSchema], branch: Optional[str] = None) -> int:
+ branch = branch or registry.default_branch
+
+ if branch not in self._branches:
+ self._branches[branch] = SchemaBranch(cache=self._cache, name=branch)
+
+ self._branches[branch].set(name=name, schema=schema)
+
+ return hash(self._branches[branch])
+
+ def has(self, name: str, branch: Optional[Union[Branch, str]] = None) -> bool:
+ try:
+ self.get(name=name, branch=branch, duplicate=False)
+ return True
+ except SchemaNotFoundError:
+ return False
+
+ def get(
+ self,
+ name: str,
+ branch: Optional[Union[Branch, str]] = None,
+ duplicate: bool = True,
+ check_branch_only: bool = False,
+ ) -> MainSchemaTypes:
+ # For now we assume that all branches are present, will see how we need to pull new branches later.
+ check_branch_only = check_branch_only and bool(branch)
+ branch = registry.get_branch_from_registry(branch=branch)
+
+ if branch.name in self._branches:
+ try:
+ return self._branches[branch.name].get(name=name, duplicate=duplicate)
+ except SchemaNotFoundError:
+ pass
+
+ if check_branch_only:
+ raise SchemaNotFoundError(
+ branch_name=branch.name, identifier=name, message=f"Unable to find the schema {name!r} in the registry"
+ )
+
+ default_branch = registry.default_branch
+ return self._branches[default_branch].get(name=name, duplicate=duplicate)
+
+ def get_node_schema(
+ self, name: str, branch: Optional[Union[Branch, str]] = None, duplicate: bool = True
+ ) -> NodeSchema:
+ schema = self.get(name=name, branch=branch, duplicate=duplicate)
+ if isinstance(schema, NodeSchema):
+ return schema
+
+ raise ValueError("The selected node is not of type NodeSchema")
+
+ def get_full(
+ self, branch: Optional[Union[Branch, str]] = None, duplicate: bool = True
+ ) -> dict[str, MainSchemaTypes]:
+ branch = registry.get_branch_from_registry(branch=branch)
+
+ branch_name = None
+ if branch.name in self._branches:
+ branch_name = branch.name
+ else:
+ branch_name = registry.default_branch
+
+ return self._branches[branch_name].get_all(duplicate=duplicate)
+
+ async def get_full_safe(
+ self, branch: Optional[Union[Branch, str]] = None
+ ) -> dict[str, Union[NodeSchema, GenericSchema]]:
+ await lock.registry.local_schema_wait()
+
+ return self.get_full(branch=branch)
+
+ def get_schema_branch(self, name: str) -> SchemaBranch:
+ if name in self._branches:
+ return self._branches[name]
+
+ self._branches[name] = SchemaBranch(cache=self._cache, name=name)
+ return self._branches[name]
+
+ def set_schema_branch(self, name: str, schema: SchemaBranch) -> None:
+ schema.name = name
+ self._branches[name] = schema
+
+ def process_schema_branch(self, name: str) -> None:
+ schema_branch = self.get_schema_branch(name=name)
+ schema_branch.process()
+
+ async def update_schema_branch(
+ self,
+ schema: SchemaBranch,
+ db: InfrahubDatabase,
+ branch: Optional[Union[Branch, str]] = None,
+ diff: Optional[SchemaDiff] = None,
+ limit: Optional[list[str]] = None,
+ update_db: bool = True,
+ ) -> None:
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ updated_schema = None
+ if update_db:
+ schema_diff = None
+ if diff:
+ schema_diff = await self.update_schema_to_db(schema=schema, db=db, branch=branch, diff=diff)
+ else:
+ await self.load_schema_to_db(schema=schema, db=db, branch=branch, limit=limit)
+ # After updating the schema into the db
+ # we need to pull a fresh version because some default value are managed/generated within the node object
+ schema_diff = None
+ if limit:
+ schema_diff = SchemaBranchDiff(
+ nodes=[name for name in list(schema.nodes.keys()) if name in limit],
+ generics=[name for name in list(schema.generics.keys()) if name in limit],
+ )
+
+ updated_schema = await self.load_schema_from_db(
+ db=db, branch=branch, schema=schema, schema_diff=schema_diff
+ )
+
+ self.set_schema_branch(name=branch.name, schema=updated_schema or schema)
+
+ def register_schema(self, schema: SchemaRoot, branch: Optional[str] = None) -> SchemaBranch:
+ """Register all nodes, generics & groups from a SchemaRoot object into the registry."""
+
+ branch = branch or registry.default_branch
+ schema_branch = self.get_schema_branch(name=branch)
+ schema_branch.load_schema(schema=schema)
+ schema_branch.process()
+ return schema_branch
+
+ async def update_schema_to_db(
+ self,
+ schema: SchemaBranch,
+ db: InfrahubDatabase,
+ diff: SchemaDiff,
+ branch: Optional[Union[str, Branch]] = None,
+ ) -> SchemaBranchDiff:
+ """Load all nodes, generics and groups from a SchemaRoot object into the database."""
+
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ item_kinds = []
+ for item_kind, item_diff in diff.added.items():
+ item = schema.get(name=item_kind, duplicate=False)
+ node = await self.load_node_to_db(node=item, branch=branch, db=db)
+ schema.set(name=item_kind, schema=node)
+ item_kinds.append(item_kind)
+
+ for item_kind, item_diff in diff.changed.items():
+ item = schema.get(name=item_kind, duplicate=False)
+ if item_diff:
+ node = await self.update_node_in_db_based_on_diff(node=item, branch=branch, db=db, diff=item_diff)
+ else:
+ node = await self.update_node_in_db(node=item, branch=branch, db=db)
+ schema.set(name=item_kind, schema=node)
+ item_kinds.append(item_kind)
+
+ for item_kind, item_diff in diff.removed.items():
+ item = schema.get(name=item_kind, duplicate=False)
+ node = await self.delete_node_in_db(node=item, branch=branch, db=db)
+ schema.delete(name=item_kind)
+
+ schema_diff = SchemaBranchDiff(
+ nodes=[name for name in schema.node_names if name in item_kinds],
+ generics=[name for name in schema.generic_names if name in item_kinds],
+ )
+ return schema_diff
+
+ async def load_schema_to_db(
+ self,
+ schema: SchemaBranch,
+ db: InfrahubDatabase,
+ branch: Optional[Union[str, Branch]] = None,
+ limit: Optional[list[str]] = None,
+ ) -> None:
+ """Load all nodes, generics and groups from a SchemaRoot object into the database."""
+
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ for item_kind in schema.node_names + schema.generic_names:
+ if item_kind == InfrahubKind.PROFILE:
+ continue
+ if limit and item_kind not in limit:
+ continue
+ item = schema.get(name=item_kind, duplicate=False)
+ if not item.id:
+ node = await self.load_node_to_db(node=item, branch=branch, db=db)
+ schema.set(name=item_kind, schema=node)
+ else:
+ node = await self.update_node_in_db(node=item, branch=branch, db=db)
+ schema.set(name=item_kind, schema=node)
+
+ async def load_node_to_db(
+ self,
+ node: Union[NodeSchema, GenericSchema],
+ db: InfrahubDatabase,
+ branch: Optional[Union[str, Branch]] = None,
+ ) -> Union[NodeSchema, GenericSchema]:
+ """Load a Node with its attributes and its relationships to the database."""
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ node_type = "SchemaNode"
+ if isinstance(node, GenericSchema):
+ node_type = "SchemaGeneric"
+
+ node_schema = self.get_node_schema(name=node_type, branch=branch, duplicate=False)
+ attribute_schema = self.get_node_schema(name="SchemaAttribute", branch=branch, duplicate=False)
+ relationship_schema = self.get_node_schema(name="SchemaRelationship", branch=branch, duplicate=False)
+
+ # Duplicate the node in order to store the IDs after inserting them in the database
+ new_node = node.duplicate()
+
+ # Create the node first
+ schema_dict = node.model_dump(exclude={"id", "state", "filters", "relationships", "attributes"})
+ obj = await Node.init(schema=node_schema, branch=branch, db=db)
+ await obj.new(**schema_dict, db=db)
+ await obj.save(db=db)
+ new_node.id = obj.id
+
+ # Then create the Attributes and the relationships
+ if isinstance(node, (NodeSchema, GenericSchema)):
+ new_node.relationships = []
+ new_node.attributes = []
+
+ for item in node.attributes:
+ new_attr = await self.create_attribute_in_db(
+ schema=attribute_schema, item=item, parent=obj, branch=branch, db=db
+ )
+ new_node.attributes.append(new_attr)
+
+ for item in node.relationships:
+ new_rel = await self.create_relationship_in_db(
+ schema=relationship_schema, item=item, parent=obj, branch=branch, db=db
+ )
+ new_node.relationships.append(new_rel)
+
+ # Save back the node with the newly created IDs in the SchemaManager
+ self.set(name=new_node.kind, schema=new_node, branch=branch.name)
+ return new_node
+
+ async def update_node_in_db(
+ self,
+ db: InfrahubDatabase,
+ node: Union[NodeSchema, GenericSchema],
+ branch: Optional[Union[str, Branch]] = None,
+ ) -> Union[NodeSchema, GenericSchema]:
+ """Update a Node with its attributes and its relationships in the database."""
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ obj = await self.get_one(id=node.get_id(), branch=branch, db=db)
+ if not obj:
+ raise SchemaNotFoundError(
+ branch_name=branch.name,
+ identifier=node.id,
+ message=f"Unable to find the Schema associated with {node.id}, {node.kind}",
+ )
+
+ schema_dict = node.model_dump(exclude=IGNORE_FOR_NODE)
+ for key, value in schema_dict.items():
+ getattr(obj, key).value = value
+
+ attribute_schema = self.get_node_schema(name="SchemaAttribute", branch=branch)
+ relationship_schema = self.get_node_schema(name="SchemaRelationship", branch=branch)
+
+ new_node = node.duplicate()
+
+ # Update the attributes and the relationships nodes as well
+ await obj.attributes.update(db=db, data=[item.id for item in node.local_attributes if item.id])
+ await obj.relationships.update(
+ db=db, data=[item.id for item in node.local_relationships if item.id and item.name != "profiles"]
+ )
+ await obj.save(db=db)
+
+ # Then Update the Attributes and the relationships
+
+ items = await self.get_many(
+ ids=[item.id for item in node.local_attributes + node.local_relationships if item.id],
+ db=db,
+ branch=branch,
+ include_owner=True,
+ include_source=True,
+ )
+
+ for item in node.local_attributes:
+ if item.id and item.id in items:
+ await self.update_attribute_in_db(item=item, attr=items[item.id], db=db)
+ elif not item.id:
+ new_attr = await self.create_attribute_in_db(
+ schema=attribute_schema, item=item, branch=branch, db=db, parent=obj
+ )
+ new_node.attributes.append(new_attr)
+
+ for item in node.local_relationships:
+ if item.id and item.id in items:
+ await self.update_relationship_in_db(item=item, rel=items[item.id], db=db)
+ elif not item.id:
+ new_rel = await self.create_relationship_in_db(
+ schema=relationship_schema, item=item, branch=branch, db=db, parent=obj
+ )
+ new_node.relationships.append(new_rel)
+
+ # Save back the node with the (potentially) newly created IDs in the SchemaManager
+ self.set(name=new_node.kind, schema=new_node, branch=branch.name)
+ return new_node
+
+ async def update_node_in_db_based_on_diff( # pylint: disable=too-many-branches,too-many-statements
+ self,
+ db: InfrahubDatabase,
+ diff: HashableModelDiff,
+ node: Union[NodeSchema, GenericSchema],
+ branch: Optional[Union[str, Branch]] = None,
+ ) -> Union[NodeSchema, GenericSchema]:
+ """Update a Node with its attributes and its relationships in the database based on a HashableModelDiff."""
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ obj = await self.get_one(id=node.get_id(), branch=branch, db=db)
+ if not obj:
+ raise SchemaNotFoundError(
+ branch_name=branch.name,
+ identifier=node.id,
+ message=f"Unable to find the Schema associated with {node.id}, {node.kind}",
+ )
+
+ properties_to_update = set(list(diff.added.keys()) + list(diff.changed.keys())) - IGNORE_FOR_NODE
+
+ if properties_to_update:
+ schema_dict = node.model_dump(exclude=IGNORE_FOR_NODE)
+ for key, value in schema_dict.items():
+ getattr(obj, key).value = value
+
+ attribute_schema = self.get_node_schema(name="SchemaAttribute", branch=branch)
+ relationship_schema = self.get_node_schema(name="SchemaRelationship", branch=branch)
+
+ new_node = node.duplicate()
+
+ # Update the attributes and the relationships nodes as well
+ if "attributes" in diff.changed:
+ await obj.attributes.update(db=db, data=[item.id for item in node.local_attributes if item.id])
+
+ if "relationships" in diff.changed:
+ await obj.relationships.update(db=db, data=[item.id for item in node.local_relationships if item.id])
+
+ await obj.save(db=db)
+
+ # Then Update the Attributes and the relationships
+ def get_attrs_rels_to_update(diff: HashableModelDiff) -> list[str]:
+ items_to_update = []
+ if "attributes" in diff.changed.keys() and diff.changed["attributes"]:
+ items_to_update.extend(list(diff.changed["attributes"].added.keys()))
+ items_to_update.extend(list(diff.changed["attributes"].changed.keys()))
+ items_to_update.extend(list(diff.changed["attributes"].removed.keys()))
+ if "relationships" in diff.changed.keys() and diff.changed["relationships"]:
+ items_to_update.extend(list(diff.changed["relationships"].added.keys()))
+ items_to_update.extend(list(diff.changed["relationships"].changed.keys()))
+ items_to_update.extend(list(diff.changed["relationships"].removed.keys()))
+ return items_to_update
+
+ attrs_rels_to_update = get_attrs_rels_to_update(diff=diff)
+
+ items = await self.get_many(
+ ids=[
+ item.id
+ for item in node.local_attributes + node.local_relationships
+ if item.id and item.name in attrs_rels_to_update
+ ],
+ db=db,
+ branch=branch,
+ include_owner=True,
+ include_source=True,
+ )
+
+ if "attributes" in diff.changed.keys() and diff.changed["attributes"]:
+ for item in node.local_attributes:
+ if item.name in diff.changed["attributes"].added:
+ created_item = await self.create_attribute_in_db(
+ schema=attribute_schema, item=item, branch=branch, db=db, parent=obj
+ )
+ new_attr = new_node.get_attribute(name=item.name)
+ new_attr.id = created_item.id
+ elif item.name in diff.changed["attributes"].changed and item.id and item.id in items:
+ await self.update_attribute_in_db(item=item, attr=items[item.id], db=db)
+ elif item.name in diff.changed["attributes"].removed and item.id and item.id in items:
+ await items[item.id].delete(db=db)
+ elif (
+ (item.name in diff.changed["attributes"].removed or item.name in diff.changed["attributes"].changed)
+ and item.id
+ and item.id not in items
+ ):
+ raise ValueError(f"Unable to find an attribute {item.name!r} to update or delete")
+
+ if "relationships" in diff.changed.keys() and diff.changed["relationships"]:
+ for item in node.local_relationships:
+ if item.name in diff.changed["relationships"].added:
+ created_rel = await self.create_relationship_in_db(
+ schema=relationship_schema, item=item, branch=branch, db=db, parent=obj
+ )
+ new_rel = new_node.get_relationship(name=item.name)
+ new_rel.id = created_rel.id
+ elif item.name in diff.changed["relationships"].changed and item.id and item.id in items:
+ await self.update_relationship_in_db(item=item, rel=items[item.id], db=db)
+ elif item.name in diff.changed["relationships"].removed and item.id and item.id in items:
+ await items[item.id].delete(db=db)
+ elif (
+ (
+ item.name in diff.changed["relationships"].removed
+ or item.name in diff.changed["relationships"].changed
+ )
+ and item.id
+ and item.id not in items
+ ):
+ raise ValueError(f"Unable to find an relationship {item.name!r} to update or delete")
+
+ # Save back the node with the (potentially) newly created IDs in the SchemaManager
+ self.set(name=new_node.kind, schema=new_node, branch=branch.name)
+ return new_node
+
+ async def delete_node_in_db(
+ self,
+ db: InfrahubDatabase,
+ node: Union[NodeSchema, GenericSchema],
+ branch: Optional[Union[str, Branch]] = None,
+ ) -> None:
+ """Delete the node with its attributes and relationships."""
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ obj = await self.get_one(id=node.get_id(), branch=branch, db=db)
+ if not obj:
+ raise SchemaNotFoundError(
+ branch_name=branch.name,
+ identifier=node.id,
+ message=f"Unable to find the Schema associated with {node.id}, {node.kind}",
+ )
+
+ # First delete the attributes and the relationships
+ items = await self.get_many(
+ ids=[item.id for item in node.local_attributes + node.local_relationships if item.id],
+ db=db,
+ branch=branch,
+ include_owner=True,
+ include_source=True,
+ )
+
+ for item in items.values():
+ await item.delete(db=db)
+
+ await obj.delete(db=db)
+
+ @staticmethod
+ async def create_attribute_in_db(
+ schema: NodeSchema, item: AttributeSchema, branch: Branch, parent: Node, db: InfrahubDatabase
+ ) -> AttributeSchema:
+ obj = await Node.init(schema=schema, branch=branch, db=db)
+ await obj.new(**item.model_dump(exclude={"id", "state", "filters"}), node=parent, db=db)
+ await obj.save(db=db)
+ new_item = item.duplicate()
+ new_item.id = obj.id
+ return new_item
+
+ @staticmethod
+ async def update_attribute_in_db(item: AttributeSchema, attr: Node, db: InfrahubDatabase) -> None:
+ item_dict = item.model_dump(exclude={"id", "state", "filters"})
+ for key, value in item_dict.items():
+ getattr(attr, key).value = value
+ await attr.save(db=db)
+
+ @staticmethod
+ async def create_relationship_in_db(
+ schema: NodeSchema, item: RelationshipSchema, branch: Branch, parent: Node, db: InfrahubDatabase
+ ) -> RelationshipSchema:
+ obj = await Node.init(schema=schema, branch=branch, db=db)
+ await obj.new(**item.model_dump(exclude={"id", "state", "filters"}), node=parent, db=db)
+ await obj.save(db=db)
+ new_item = item.duplicate()
+ new_item.id = obj.id
+ return new_item
+
+ @staticmethod
+ async def update_relationship_in_db(item: RelationshipSchema, rel: Node, db: InfrahubDatabase) -> None:
+ item_dict = item.model_dump(exclude={"id", "state", "filters"})
+ for key, value in item_dict.items():
+ getattr(rel, key).value = value
+ await rel.save(db=db)
+
+ async def load_schema(
+ self,
+ db: InfrahubDatabase,
+ branch: Optional[Union[str, Branch]] = None,
+ ) -> SchemaBranch:
+ """Load the schema either from the cache or from the database"""
+ branch = await registry.get_branch(branch=branch, db=db)
+
+ if not branch.is_default and branch.origin_branch:
+ origin_branch: Branch = await registry.get_branch(branch=branch.origin_branch, db=db)
+
+ if origin_branch.schema_hash.main == branch.schema_hash.main:
+ origin_schema = self.get_schema_branch(name=origin_branch.name)
+ new_branch_schema = origin_schema.duplicate()
+ self.set_schema_branch(name=branch.name, schema=new_branch_schema)
+ log.info("Loading schema from cache")
+ return new_branch_schema
+
+ current_schema = self.get_schema_branch(name=branch.name)
+ schema_diff = current_schema.get_hash_full().compare(branch.schema_hash)
+ branch_schema = await self.load_schema_from_db(
+ db=db, branch=branch, schema=current_schema, schema_diff=schema_diff
+ )
+ branch_schema.clear_cache()
+ self.set_schema_branch(name=branch.name, schema=branch_schema)
+ return branch_schema
+
+ async def load_schema_from_db(
+ self,
+ db: InfrahubDatabase,
+ branch: Optional[Union[str, Branch]] = None,
+ schema: Optional[SchemaBranch] = None,
+ schema_diff: Optional[SchemaBranchDiff] = None,
+ at: Optional[Timestamp] = None,
+ validate_schema: bool = True,
+ ) -> SchemaBranch:
+ """Query all the node of type NodeSchema and GenericSchema from the database and convert them to their respective type.
+
+ Args:
+ db: Database Driver
+ branch: Name of the branch to load the schema from. Defaults to None.
+ schema: (Optional) If a schema is provided, it will be updated with the latest value, if not a new one will be created.
+ schema_diff: (Optional). list of nodes, generics & groups to query
+
+ Returns:
+ SchemaBranch
+ """
+
+ branch = await registry.get_branch(branch=branch, db=db)
+ schema = schema or SchemaBranch(cache=self._cache, name=branch.name)
+
+ # If schema_diff has been provided, we need to build the proper filters for the queries based on the namespace and the name of the object.
+ # the namespace and the name will be extracted from the kind with the function `parse_node_kind`
+ filters = {"generics": {}, "nodes": {}}
+ has_filters = False
+
+ # If a diff is provided but is empty there is nothing to query
+ if schema_diff is not None and not schema_diff:
+ return schema
+
+ if schema_diff:
+ log.info("Loading schema from DB", schema_to_update=schema_diff.to_list())
+
+ for node_type in list(filters.keys()):
+ filter_value = {
+ "namespace__values": list(
+ {parse_node_kind(item).namespace for item in getattr(schema_diff, node_type)}
+ ),
+ "name__values": list({parse_node_kind(item).name for item in getattr(schema_diff, node_type)}),
+ }
+
+ if filter_value["namespace__values"]:
+ filters[node_type] = filter_value
+ has_filters = True
+
+ if not has_filters or filters["generics"]:
+ generic_schema = self.get(name="SchemaGeneric", branch=branch)
+ for schema_node in await self.query(
+ schema=generic_schema,
+ branch=branch,
+ at=at,
+ filters=filters["generics"],
+ prefetch_relationships=True,
+ db=db,
+ ):
+ kind = f"{schema_node.namespace.value}{schema_node.name.value}"
+ schema.set(
+ name=kind,
+ schema=await self.convert_generic_schema_to_schema(schema_node=schema_node, db=db),
+ )
+
+ if not has_filters or filters["nodes"]:
+ node_schema = self.get(name="SchemaNode", branch=branch)
+ for schema_node in await self.query(
+ schema=node_schema, branch=branch, at=at, filters=filters["nodes"], prefetch_relationships=True, db=db
+ ):
+ kind = f"{schema_node.namespace.value}{schema_node.name.value}"
+ schema.set(
+ name=kind,
+ schema=await self.convert_node_schema_to_schema(schema_node=schema_node, db=db),
+ )
+
+ schema.process(validate_schema=validate_schema)
+
+ return schema
+
+ @classmethod
+ async def _prepare_node_data(cls, schema_node: Node, db: InfrahubDatabase) -> dict[str, Any]:
+ node_data = {"id": schema_node.id}
+
+ # First pull all the local attributes at the top level, then convert all the local relationships
+ # for a standard node_schema, the relationships will be attributes and relationships
+ for attr_name in schema_node._attributes:
+ attr = getattr(schema_node, attr_name)
+ node_data[attr_name] = attr.get_value()
+
+ for rel_name in schema_node._relationships:
+ if rel_name not in node_data:
+ if rel_name == "profiles":
+ continue
+ node_data[rel_name] = []
+
+ rm = getattr(schema_node, rel_name)
+ for rel in await rm.get(db=db):
+ item = await rel.get_peer(db=db)
+ item_data = {"id": item.id}
+ for item_name in item._attributes:
+ item_attr = getattr(item, item_name)
+ item_data[item_name] = item_attr.get_value()
+
+ node_data[rel_name].append(item_data)
+ return node_data
+
+ @classmethod
+ async def convert_node_schema_to_schema(cls, schema_node: Node, db: InfrahubDatabase) -> NodeSchema:
+ """Convert a schema_node object loaded from the database into NodeSchema object."""
+ node_data = await cls._prepare_node_data(schema_node=schema_node, db=db)
+ return NodeSchema(**node_data)
+
+ @classmethod
+ async def convert_generic_schema_to_schema(cls, schema_node: Node, db: InfrahubDatabase) -> GenericSchema:
+ """Convert a schema_node object loaded from the database into GenericSchema object."""
+ node_data = await cls._prepare_node_data(schema_node=schema_node, db=db)
+ return GenericSchema(**node_data)
diff --git a/backend/infrahub/core/schema_manager.py b/backend/infrahub/core/schema/schema_branch.py
similarity index 67%
rename from backend/infrahub/core/schema_manager.py
rename to backend/infrahub/core/schema/schema_branch.py
index eac391f9e9..116cf5ca42 100644
--- a/backend/infrahub/core/schema_manager.py
+++ b/backend/infrahub/core/schema/schema_branch.py
@@ -4,19 +4,17 @@
import hashlib
from collections import defaultdict
from itertools import chain
-from typing import TYPE_CHECKING, Any, Optional, Union
+from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Union
from infrahub_sdk.topological_sort import DependencyCycleExistsError, topological_sort
from infrahub_sdk.utils import compare_lists, deep_merge_dict, duplicates, intersection
-from pydantic import BaseModel
+from typing_extensions import Self
-from infrahub import lock
from infrahub.core.constants import (
RESERVED_ATTR_GEN_NAMES,
RESERVED_ATTR_REL_NAMES,
RESTRICTED_NAMESPACES,
BranchSupportType,
- FilterSchemaKind,
HashableModelState,
InfrahubKind,
RelationshipCardinality,
@@ -25,23 +23,17 @@
RelationshipKind,
SchemaElementPathType,
)
-from infrahub.core.manager import NodeManager
from infrahub.core.migrations import MIGRATION_MAP
from infrahub.core.models import (
HashableModelDiff,
- SchemaBranchDiff,
SchemaBranchHash,
SchemaDiff,
SchemaUpdateValidationResult,
)
-from infrahub.core.node import Node
-from infrahub.core.property import FlagPropertyMixin, NodePropertyMixin
-from infrahub.core.registry import registry
from infrahub.core.schema import (
AttributePathParsingError,
AttributeSchema,
BaseNodeSchema,
- FilterSchema,
GenericSchema,
MainSchemaTypes,
NodeSchema,
@@ -49,10 +41,8 @@
RelationshipSchema,
SchemaAttributePath,
SchemaRoot,
- internal_schema,
)
from infrahub.core.schema.definitions.core import core_profile_schema_definition
-from infrahub.core.utils import parse_node_kind
from infrahub.core.validators import CONSTRAINT_VALIDATOR_MAP
from infrahub.exceptions import SchemaNotFoundError, ValidationError
from infrahub.graphql.manager import GraphQLSchemaManager
@@ -61,43 +51,22 @@
from infrahub.utils import format_label
from infrahub.visuals import select_color
+from .constants import INTERNAL_SCHEMA_NODE_KINDS, SchemaNamespace
+
log = get_logger()
if TYPE_CHECKING:
from graphql import GraphQLSchema
+ from pydantic import ValidationInfo
- from infrahub.core.branch import Branch
- from infrahub.core.timestamp import Timestamp
- from infrahub.database import InfrahubDatabase
# pylint: disable=redefined-builtin,too-many-public-methods,too-many-lines
-INTERNAL_SCHEMA_NODE_KINDS = [node["namespace"] + node["name"] for node in internal_schema["nodes"]]
-
-SUPPORTED_SCHEMA_EXTENSION_TYPE = ["NodeExtensionSchema"]
-
-KIND_FILTER_MAP = {
- "Text": FilterSchemaKind.TEXT,
- "String": FilterSchemaKind.TEXT,
- "Number": FilterSchemaKind.NUMBER,
- "Integer": FilterSchemaKind.NUMBER,
- "Boolean": FilterSchemaKind.BOOLEAN,
- "Checkbox": FilterSchemaKind.BOOLEAN,
- "Dropdown": FilterSchemaKind.TEXT,
-}
-
-IGNORE_FOR_NODE = {"id", "state", "filters", "relationships", "attributes"}
-
-
-class SchemaNamespace(BaseModel):
- name: str
- user_editable: bool
-
class SchemaBranch:
- def __init__(self, cache: dict, name: Optional[str] = None, data: Optional[dict[str, int]] = None):
+ def __init__(self, cache: dict, name: str | None = None, data: dict[str, dict[str, str]] | None = None):
self._cache: dict[str, Union[NodeSchema, GenericSchema]] = cache
- self.name: Optional[str] = name
+ self.name: str | None = name
self.nodes: dict[str, str] = {}
self.generics: dict[str, str] = {}
self.profiles: dict[str, str] = {}
@@ -109,6 +78,18 @@ def __init__(self, cache: dict, name: Optional[str] = None, data: Optional[dict[
self.generics = data.get("generics", {})
self.profiles = data.get("profiles", {})
+ @classmethod
+ def __get_validators__(cls) -> Iterator[Callable[..., Any]]: # noqa: PLW3201
+ yield cls.validate
+
+ @classmethod
+ def validate(cls, v: Any, info: ValidationInfo) -> Self: # pylint: disable=unused-argument
+ if isinstance(v, cls):
+ return v
+ if isinstance(v, dict):
+ return cls.from_dict_schema_object(data=v)
+ raise ValueError("must be a class or a dict")
+
@property
def node_names(self) -> list[str]:
return list(self.nodes.keys())
@@ -163,7 +144,28 @@ def to_dict_schema_object(self, duplicate: bool = False) -> dict[str, dict[str,
"generics": {name: self.get(name, duplicate=duplicate) for name in self.generics},
}
- def clear_cache(self):
+ @classmethod
+ def from_dict_schema_object(cls, data: dict) -> Self:
+ type_mapping = {
+ "nodes": NodeSchema,
+ "generics": GenericSchema,
+ "profiles": ProfileSchema,
+ }
+
+ cache: dict[str, MainSchemaTypes] = {}
+ nodes: dict[str, dict[str, str]] = {"nodes": {}, "generics": {}, "profiles": {}}
+
+ for node_type, node_class in type_mapping.items():
+ for node_name, node_data in data[node_type].items():
+ node: MainSchemaTypes = node_class(**node_data)
+ node_hash = node.get_hash()
+ nodes[node_type][node_name] = node_hash
+
+ cache[node_hash] = node
+
+ return cls(cache=cache, data=nodes)
+
+ def clear_cache(self) -> None:
self._graphql_manager = None
self._graphql_schema = None
@@ -501,7 +503,6 @@ def process_validate(self) -> None:
def process_post_validation(self) -> None:
self.add_groups()
self.add_hierarchy()
- self.process_filters()
self.generate_weight()
self.process_labels()
self.process_dropdowns()
@@ -756,7 +757,7 @@ def validate_default_filters(self) -> None:
element_name="default_filter",
)
- def validate_default_values(self):
+ def validate_default_values(self) -> None:
for name in self.generic_names + self.node_names:
node_schema = self.get(name=name, duplicate=False)
for node_attr in node_schema.local_attributes:
@@ -1253,22 +1254,6 @@ def process_default_values(self) -> None:
self.set(name=name, schema=node)
- def process_filters(self) -> Node:
- # Generate the filters for all nodes and generics, at the NodeSchema and at the relationships level.
- for name in self.all_names:
- node = self.get(name=name)
- node.filters = self.generate_filters(schema=node, include_relationships=True)
-
- for rel in node.relationships:
- try:
- peer_schema = self.get(name=rel.peer, duplicate=False)
- except SchemaNotFoundError:
- continue
-
- rel.filters = self.generate_filters(schema=peer_schema, include_relationships=False)
-
- self.set(name=name, schema=node)
-
def process_cardinality_counts(self) -> None:
"""Ensure that all relationships with a cardinality of ONE have a min_count and max_count of 1."""
# pylint: disable=too-many-branches
@@ -1601,709 +1586,3 @@ def generate_profile_from_node(self, node: NodeSchema) -> ProfileSchema:
profile.attributes.append(attr)
return profile
-
- def generate_filters(
- self, schema: Union[NodeSchema, GenericSchema], include_relationships: bool = False
- ) -> list[FilterSchema]:
- """Generate the FilterSchema for a given NodeSchema or GenericSchema object."""
- # pylint: disable=too-many-branches
- filters = []
-
- filters.append(FilterSchema(name="ids", kind=FilterSchemaKind.LIST))
- if schema.human_friendly_id:
- filters.append(FilterSchema(name="hfid", kind=FilterSchemaKind.LIST))
-
- for attr in schema.attributes:
- filter_kind = KIND_FILTER_MAP.get(attr.kind, None)
- if not filter_kind:
- continue
-
- filter = FilterSchema(name=f"{attr.name}__value", kind=filter_kind)
-
- if attr.enum:
- filter.enum = attr.enum
-
- filters.append(filter)
- filters.append(FilterSchema(name=f"{attr.name}__values", kind=FilterSchemaKind.LIST))
-
- for flag_prop in FlagPropertyMixin._flag_properties:
- filters.append(FilterSchema(name=f"{attr.name}__{flag_prop}", kind=FilterSchemaKind.BOOLEAN))
- for node_prop in NodePropertyMixin._node_properties:
- filters.append(FilterSchema(name=f"{attr.name}__{node_prop}__id", kind=FilterSchemaKind.TEXT))
-
- # Define generic filters, mainly used to query all nodes associated with a given account
- if include_relationships:
- filters.append(FilterSchema(name="any__value", kind=FilterSchemaKind.TEXT))
- for flag_prop in FlagPropertyMixin._flag_properties:
- filters.append(FilterSchema(name=f"any__{flag_prop}", kind=FilterSchemaKind.BOOLEAN))
- for node_prop in NodePropertyMixin._node_properties:
- filters.append(FilterSchema(name=f"any__{node_prop}__id", kind=FilterSchemaKind.TEXT))
-
- if not include_relationships:
- return filters
-
- for rel in schema.relationships:
- if rel.kind not in ["Attribute", "Parent"]:
- continue
- filters.append(FilterSchema(name=f"{rel.name}__ids", kind=FilterSchemaKind.LIST, object_kind=rel.peer))
- peer_schema = self.get(name=rel.peer, duplicate=False)
-
- for attr in peer_schema.attributes:
- filter_kind = KIND_FILTER_MAP.get(attr.kind, None)
- if not filter_kind:
- continue
-
- filter = FilterSchema(name=f"{rel.name}__{attr.name}__value", kind=filter_kind)
-
- if attr.enum:
- filter.enum = attr.enum
-
- filters.append(filter)
- filters.append(FilterSchema(name=f"{rel.name}__{attr.name}__values", kind=FilterSchemaKind.LIST))
-
- for flag_prop in FlagPropertyMixin._flag_properties:
- filters.append(
- FilterSchema(name=f"{rel.name}__{attr.name}__{flag_prop}", kind=FilterSchemaKind.BOOLEAN)
- )
- for node_prop in NodePropertyMixin._node_properties:
- filters.append(
- FilterSchema(name=f"{rel.name}__{attr.name}__{node_prop}__id", kind=FilterSchemaKind.TEXT)
- )
-
- return filters
-
-
-# pylint: disable=too-many-public-methods
-class SchemaManager(NodeManager):
- def __init__(self) -> None:
- self._cache: dict[int, Any] = {}
- self._branches: dict[str, SchemaBranch] = {}
-
- def _get_from_cache(self, key: int) -> Any:
- return self._cache[key]
-
- def set(self, name: str, schema: Union[NodeSchema, GenericSchema], branch: Optional[str] = None) -> int:
- branch = branch or registry.default_branch
-
- if branch not in self._branches:
- self._branches[branch] = SchemaBranch(cache=self._cache, name=branch)
-
- self._branches[branch].set(name=name, schema=schema)
-
- return hash(self._branches[branch])
-
- def has(self, name: str, branch: Optional[Union[Branch, str]] = None) -> bool:
- try:
- self.get(name=name, branch=branch, duplicate=False)
- return True
- except SchemaNotFoundError:
- return False
-
- def get(
- self,
- name: str,
- branch: Optional[Union[Branch, str]] = None,
- duplicate: bool = True,
- check_branch_only: bool = False,
- ) -> MainSchemaTypes:
- # For now we assume that all branches are present, will see how we need to pull new branches later.
- check_branch_only = check_branch_only and bool(branch)
- branch = registry.get_branch_from_registry(branch=branch)
-
- if branch.name in self._branches:
- try:
- return self._branches[branch.name].get(name=name, duplicate=duplicate)
- except SchemaNotFoundError:
- pass
-
- if check_branch_only:
- raise SchemaNotFoundError(
- branch_name=branch.name, identifier=name, message=f"Unable to find the schema {name!r} in the registry"
- )
-
- default_branch = registry.default_branch
- return self._branches[default_branch].get(name=name, duplicate=duplicate)
-
- def get_node_schema(
- self, name: str, branch: Optional[Union[Branch, str]] = None, duplicate: bool = True
- ) -> NodeSchema:
- schema = self.get(name=name, branch=branch, duplicate=duplicate)
- if isinstance(schema, NodeSchema):
- return schema
-
- raise ValueError("The selected node is not of type NodeSchema")
-
- def get_full(
- self, branch: Optional[Union[Branch, str]] = None, duplicate: bool = True
- ) -> dict[str, MainSchemaTypes]:
- branch = registry.get_branch_from_registry(branch=branch)
-
- branch_name = None
- if branch.name in self._branches:
- branch_name = branch.name
- else:
- branch_name = registry.default_branch
-
- return self._branches[branch_name].get_all(duplicate=duplicate)
-
- async def get_full_safe(
- self, branch: Optional[Union[Branch, str]] = None
- ) -> dict[str, Union[NodeSchema, GenericSchema]]:
- await lock.registry.local_schema_wait()
-
- return self.get_full(branch=branch)
-
- def get_schema_branch(self, name: str) -> SchemaBranch:
- if name in self._branches:
- return self._branches[name]
-
- self._branches[name] = SchemaBranch(cache=self._cache, name=name)
- return self._branches[name]
-
- def set_schema_branch(self, name: str, schema: SchemaBranch) -> None:
- schema.name = name
- self._branches[name] = schema
-
- def process_schema_branch(self, name: str) -> None:
- schema_branch = self.get_schema_branch(name=name)
- schema_branch.process()
-
- async def update_schema_branch(
- self,
- schema: SchemaBranch,
- db: InfrahubDatabase,
- branch: Optional[Union[Branch, str]] = None,
- diff: Optional[SchemaDiff] = None,
- limit: Optional[list[str]] = None,
- update_db: bool = True,
- ) -> None:
- branch = await registry.get_branch(branch=branch, db=db)
-
- updated_schema = None
- if update_db:
- schema_diff = None
- if diff:
- schema_diff = await self.update_schema_to_db(schema=schema, db=db, branch=branch, diff=diff)
- else:
- await self.load_schema_to_db(schema=schema, db=db, branch=branch, limit=limit)
- # After updating the schema into the db
- # we need to pull a fresh version because some default value are managed/generated within the node object
- schema_diff = None
- if limit:
- schema_diff = SchemaBranchDiff(
- nodes=[name for name in list(schema.nodes.keys()) if name in limit],
- generics=[name for name in list(schema.generics.keys()) if name in limit],
- )
-
- updated_schema = await self.load_schema_from_db(
- db=db, branch=branch, schema=schema, schema_diff=schema_diff
- )
-
- self.set_schema_branch(name=branch.name, schema=updated_schema or schema)
-
- def register_schema(self, schema: SchemaRoot, branch: Optional[str] = None) -> SchemaBranch:
- """Register all nodes, generics & groups from a SchemaRoot object into the registry."""
-
- branch = branch or registry.default_branch
- schema_branch = self.get_schema_branch(name=branch)
- schema_branch.load_schema(schema=schema)
- schema_branch.process()
- return schema_branch
-
- async def update_schema_to_db(
- self,
- schema: SchemaBranch,
- db: InfrahubDatabase,
- diff: SchemaDiff,
- branch: Optional[Union[str, Branch]] = None,
- ) -> SchemaBranchDiff:
- """Load all nodes, generics and groups from a SchemaRoot object into the database."""
-
- branch = await registry.get_branch(branch=branch, db=db)
-
- item_kinds = []
- for item_kind, item_diff in diff.added.items():
- item = schema.get(name=item_kind, duplicate=False)
- node = await self.load_node_to_db(node=item, branch=branch, db=db)
- schema.set(name=item_kind, schema=node)
- item_kinds.append(item_kind)
-
- for item_kind, item_diff in diff.changed.items():
- item = schema.get(name=item_kind, duplicate=False)
- if item_diff:
- node = await self.update_node_in_db_based_on_diff(node=item, branch=branch, db=db, diff=item_diff)
- else:
- node = await self.update_node_in_db(node=item, branch=branch, db=db)
- schema.set(name=item_kind, schema=node)
- item_kinds.append(item_kind)
-
- for item_kind, item_diff in diff.removed.items():
- item = schema.get(name=item_kind, duplicate=False)
- node = await self.delete_node_in_db(node=item, branch=branch, db=db)
- schema.delete(name=item_kind)
-
- schema_diff = SchemaBranchDiff(
- nodes=[name for name in schema.node_names if name in item_kinds],
- generics=[name for name in schema.generic_names if name in item_kinds],
- )
- return schema_diff
-
- async def load_schema_to_db(
- self,
- schema: SchemaBranch,
- db: InfrahubDatabase,
- branch: Optional[Union[str, Branch]] = None,
- limit: Optional[list[str]] = None,
- ) -> None:
- """Load all nodes, generics and groups from a SchemaRoot object into the database."""
-
- branch = await registry.get_branch(branch=branch, db=db)
-
- for item_kind in schema.node_names + schema.generic_names:
- if item_kind == InfrahubKind.PROFILE:
- continue
- if limit and item_kind not in limit:
- continue
- item = schema.get(name=item_kind, duplicate=False)
- if not item.id:
- node = await self.load_node_to_db(node=item, branch=branch, db=db)
- schema.set(name=item_kind, schema=node)
- else:
- node = await self.update_node_in_db(node=item, branch=branch, db=db)
- schema.set(name=item_kind, schema=node)
-
- async def load_node_to_db(
- self,
- node: Union[NodeSchema, GenericSchema],
- db: InfrahubDatabase,
- branch: Optional[Union[str, Branch]] = None,
- ) -> Union[NodeSchema, GenericSchema]:
- """Load a Node with its attributes and its relationships to the database."""
- branch = await registry.get_branch(branch=branch, db=db)
-
- node_type = "SchemaNode"
- if isinstance(node, GenericSchema):
- node_type = "SchemaGeneric"
-
- node_schema = self.get_node_schema(name=node_type, branch=branch, duplicate=False)
- attribute_schema = self.get_node_schema(name="SchemaAttribute", branch=branch, duplicate=False)
- relationship_schema = self.get_node_schema(name="SchemaRelationship", branch=branch, duplicate=False)
-
- # Duplicate the node in order to store the IDs after inserting them in the database
- new_node = node.duplicate()
-
- # Create the node first
- schema_dict = node.model_dump(exclude={"id", "state", "filters", "relationships", "attributes"})
- obj = await Node.init(schema=node_schema, branch=branch, db=db)
- await obj.new(**schema_dict, db=db)
- await obj.save(db=db)
- new_node.id = obj.id
-
- # Then create the Attributes and the relationships
- if isinstance(node, (NodeSchema, GenericSchema)):
- new_node.relationships = []
- new_node.attributes = []
-
- for item in node.attributes:
- new_attr = await self.create_attribute_in_db(
- schema=attribute_schema, item=item, parent=obj, branch=branch, db=db
- )
- new_node.attributes.append(new_attr)
-
- for item in node.relationships:
- new_rel = await self.create_relationship_in_db(
- schema=relationship_schema, item=item, parent=obj, branch=branch, db=db
- )
- new_node.relationships.append(new_rel)
-
- # Save back the node with the newly created IDs in the SchemaManager
- self.set(name=new_node.kind, schema=new_node, branch=branch.name)
- return new_node
-
- async def update_node_in_db(
- self,
- db: InfrahubDatabase,
- node: Union[NodeSchema, GenericSchema],
- branch: Optional[Union[str, Branch]] = None,
- ) -> Union[NodeSchema, GenericSchema]:
- """Update a Node with its attributes and its relationships in the database."""
- branch = await registry.get_branch(branch=branch, db=db)
-
- obj = await self.get_one(id=node.get_id(), branch=branch, db=db)
- if not obj:
- raise SchemaNotFoundError(
- branch_name=branch.name,
- identifier=node.id,
- message=f"Unable to find the Schema associated with {node.id}, {node.kind}",
- )
-
- schema_dict = node.model_dump(exclude=IGNORE_FOR_NODE)
- for key, value in schema_dict.items():
- getattr(obj, key).value = value
-
- attribute_schema = self.get_node_schema(name="SchemaAttribute", branch=branch)
- relationship_schema = self.get_node_schema(name="SchemaRelationship", branch=branch)
-
- new_node = node.duplicate()
-
- # Update the attributes and the relationships nodes as well
- await obj.attributes.update(db=db, data=[item.id for item in node.local_attributes if item.id])
- await obj.relationships.update(
- db=db, data=[item.id for item in node.local_relationships if item.id and item.name != "profiles"]
- )
- await obj.save(db=db)
-
- # Then Update the Attributes and the relationships
-
- items = await self.get_many(
- ids=[item.id for item in node.local_attributes + node.local_relationships if item.id],
- db=db,
- branch=branch,
- include_owner=True,
- include_source=True,
- )
-
- for item in node.local_attributes:
- if item.id and item.id in items:
- await self.update_attribute_in_db(item=item, attr=items[item.id], db=db)
- elif not item.id:
- new_attr = await self.create_attribute_in_db(
- schema=attribute_schema, item=item, branch=branch, db=db, parent=obj
- )
- new_node.attributes.append(new_attr)
-
- for item in node.local_relationships:
- if item.id and item.id in items:
- await self.update_relationship_in_db(item=item, rel=items[item.id], db=db)
- elif not item.id:
- new_rel = await self.create_relationship_in_db(
- schema=relationship_schema, item=item, branch=branch, db=db, parent=obj
- )
- new_node.relationships.append(new_rel)
-
- # Save back the node with the (potentially) newly created IDs in the SchemaManager
- self.set(name=new_node.kind, schema=new_node, branch=branch.name)
- return new_node
-
- async def update_node_in_db_based_on_diff( # pylint: disable=too-many-branches,too-many-statements
- self,
- db: InfrahubDatabase,
- diff: HashableModelDiff,
- node: Union[NodeSchema, GenericSchema],
- branch: Optional[Union[str, Branch]] = None,
- ) -> Union[NodeSchema, GenericSchema]:
- """Update a Node with its attributes and its relationships in the database based on a HashableModelDiff."""
- branch = await registry.get_branch(branch=branch, db=db)
-
- obj = await self.get_one(id=node.get_id(), branch=branch, db=db)
- if not obj:
- raise SchemaNotFoundError(
- branch_name=branch.name,
- identifier=node.id,
- message=f"Unable to find the Schema associated with {node.id}, {node.kind}",
- )
-
- properties_to_update = set(list(diff.added.keys()) + list(diff.changed.keys())) - IGNORE_FOR_NODE
-
- if properties_to_update:
- schema_dict = node.model_dump(exclude=IGNORE_FOR_NODE)
- for key, value in schema_dict.items():
- getattr(obj, key).value = value
-
- attribute_schema = self.get_node_schema(name="SchemaAttribute", branch=branch)
- relationship_schema = self.get_node_schema(name="SchemaRelationship", branch=branch)
-
- new_node = node.duplicate()
-
- # Update the attributes and the relationships nodes as well
- if "attributes" in diff.changed:
- await obj.attributes.update(db=db, data=[item.id for item in node.local_attributes if item.id])
-
- if "relationships" in diff.changed:
- await obj.relationships.update(db=db, data=[item.id for item in node.local_relationships if item.id])
-
- await obj.save(db=db)
-
- # Then Update the Attributes and the relationships
- def get_attrs_rels_to_update(diff: HashableModelDiff) -> list[str]:
- items_to_update = []
- if "attributes" in diff.changed.keys() and diff.changed["attributes"]:
- items_to_update.extend(list(diff.changed["attributes"].added.keys()))
- items_to_update.extend(list(diff.changed["attributes"].changed.keys()))
- items_to_update.extend(list(diff.changed["attributes"].removed.keys()))
- if "relationships" in diff.changed.keys() and diff.changed["relationships"]:
- items_to_update.extend(list(diff.changed["relationships"].added.keys()))
- items_to_update.extend(list(diff.changed["relationships"].changed.keys()))
- items_to_update.extend(list(diff.changed["relationships"].removed.keys()))
- return items_to_update
-
- attrs_rels_to_update = get_attrs_rels_to_update(diff=diff)
-
- items = await self.get_many(
- ids=[
- item.id
- for item in node.local_attributes + node.local_relationships
- if item.id and item.name in attrs_rels_to_update
- ],
- db=db,
- branch=branch,
- include_owner=True,
- include_source=True,
- )
-
- if "attributes" in diff.changed.keys() and diff.changed["attributes"]:
- for item in node.local_attributes:
- if item.name in diff.changed["attributes"].added:
- created_item = await self.create_attribute_in_db(
- schema=attribute_schema, item=item, branch=branch, db=db, parent=obj
- )
- new_attr = new_node.get_attribute(name=item.name)
- new_attr.id = created_item.id
- elif item.name in diff.changed["attributes"].changed and item.id and item.id in items:
- await self.update_attribute_in_db(item=item, attr=items[item.id], db=db)
- elif item.name in diff.changed["attributes"].removed and item.id and item.id in items:
- await items[item.id].delete(db=db)
- elif (
- (item.name in diff.changed["attributes"].removed or item.name in diff.changed["attributes"].changed)
- and item.id
- and item.id not in items
- ):
- raise ValueError(f"Unable to find an attribute {item.name!r} to update or delete")
-
- if "relationships" in diff.changed.keys() and diff.changed["relationships"]:
- for item in node.local_relationships:
- if item.name in diff.changed["relationships"].added:
- created_rel = await self.create_relationship_in_db(
- schema=relationship_schema, item=item, branch=branch, db=db, parent=obj
- )
- new_rel = new_node.get_relationship(name=item.name)
- new_rel.id = created_rel.id
- elif item.name in diff.changed["relationships"].changed and item.id and item.id in items:
- await self.update_relationship_in_db(item=item, rel=items[item.id], db=db)
- elif item.name in diff.changed["relationships"].removed and item.id and item.id in items:
- await items[item.id].delete(db=db)
- elif (
- (
- item.name in diff.changed["relationships"].removed
- or item.name in diff.changed["relationships"].changed
- )
- and item.id
- and item.id not in items
- ):
- raise ValueError(f"Unable to find an relationship {item.name!r} to update or delete")
-
- # Save back the node with the (potentially) newly created IDs in the SchemaManager
- self.set(name=new_node.kind, schema=new_node, branch=branch.name)
- return new_node
-
- async def delete_node_in_db(
- self,
- db: InfrahubDatabase,
- node: Union[NodeSchema, GenericSchema],
- branch: Optional[Union[str, Branch]] = None,
- ) -> None:
- """Delete the node with its attributes and relationships."""
- branch = await registry.get_branch(branch=branch, db=db)
-
- obj = await self.get_one(id=node.get_id(), branch=branch, db=db)
- if not obj:
- raise SchemaNotFoundError(
- branch_name=branch.name,
- identifier=node.id,
- message=f"Unable to find the Schema associated with {node.id}, {node.kind}",
- )
-
- # First delete the attributes and the relationships
- items = await self.get_many(
- ids=[item.id for item in node.local_attributes + node.local_relationships if item.id],
- db=db,
- branch=branch,
- include_owner=True,
- include_source=True,
- )
-
- for item in items.values():
- await item.delete(db=db)
-
- await obj.delete(db=db)
-
- @staticmethod
- async def create_attribute_in_db(
- schema: NodeSchema, item: AttributeSchema, branch: Branch, parent: Node, db: InfrahubDatabase
- ) -> AttributeSchema:
- obj = await Node.init(schema=schema, branch=branch, db=db)
- await obj.new(**item.model_dump(exclude={"id", "state", "filters"}), node=parent, db=db)
- await obj.save(db=db)
- new_item = item.duplicate()
- new_item.id = obj.id
- return new_item
-
- @staticmethod
- async def update_attribute_in_db(item: AttributeSchema, attr: Node, db: InfrahubDatabase) -> None:
- item_dict = item.model_dump(exclude={"id", "state", "filters"})
- for key, value in item_dict.items():
- getattr(attr, key).value = value
- await attr.save(db=db)
-
- @staticmethod
- async def create_relationship_in_db(
- schema: NodeSchema, item: RelationshipSchema, branch: Branch, parent: Node, db: InfrahubDatabase
- ) -> RelationshipSchema:
- obj = await Node.init(schema=schema, branch=branch, db=db)
- await obj.new(**item.model_dump(exclude={"id", "state", "filters"}), node=parent, db=db)
- await obj.save(db=db)
- new_item = item.duplicate()
- new_item.id = obj.id
- return new_item
-
- @staticmethod
- async def update_relationship_in_db(item: RelationshipSchema, rel: Node, db: InfrahubDatabase) -> None:
- item_dict = item.model_dump(exclude={"id", "state", "filters"})
- for key, value in item_dict.items():
- getattr(rel, key).value = value
- await rel.save(db=db)
-
- async def load_schema(
- self,
- db: InfrahubDatabase,
- branch: Optional[Union[str, Branch]] = None,
- ) -> SchemaBranch:
- """Load the schema either from the cache or from the database"""
- branch = await registry.get_branch(branch=branch, db=db)
-
- if not branch.is_default and branch.origin_branch:
- origin_branch: Branch = await registry.get_branch(branch=branch.origin_branch, db=db)
-
- if origin_branch.schema_hash.main == branch.schema_hash.main:
- origin_schema = self.get_schema_branch(name=origin_branch.name)
- new_branch_schema = origin_schema.duplicate()
- self.set_schema_branch(name=branch.name, schema=new_branch_schema)
- log.info("Loading schema from cache")
- return new_branch_schema
-
- current_schema = self.get_schema_branch(name=branch.name)
- schema_diff = current_schema.get_hash_full().compare(branch.schema_hash)
- branch_schema = await self.load_schema_from_db(
- db=db, branch=branch, schema=current_schema, schema_diff=schema_diff
- )
- branch_schema.clear_cache()
- self.set_schema_branch(name=branch.name, schema=branch_schema)
- return branch_schema
-
- async def load_schema_from_db(
- self,
- db: InfrahubDatabase,
- branch: Optional[Union[str, Branch]] = None,
- schema: Optional[SchemaBranch] = None,
- schema_diff: Optional[SchemaBranchDiff] = None,
- at: Optional[Timestamp] = None,
- validate_schema: bool = True,
- ) -> SchemaBranch:
- """Query all the node of type NodeSchema and GenericSchema from the database and convert them to their respective type.
-
- Args:
- db: Database Driver
- branch: Name of the branch to load the schema from. Defaults to None.
- schema: (Optional) If a schema is provided, it will be updated with the latest value, if not a new one will be created.
- schema_diff: (Optional). list of nodes, generics & groups to query
-
- Returns:
- SchemaBranch
- """
-
- branch = await registry.get_branch(branch=branch, db=db)
- schema = schema or SchemaBranch(cache=self._cache, name=branch.name)
-
- # If schema_diff has been provided, we need to build the proper filters for the queries based on the namespace and the name of the object.
- # the namespace and the name will be extracted from the kind with the function `parse_node_kind`
- filters = {"generics": {}, "nodes": {}}
- has_filters = False
-
- # If a diff is provided but is empty there is nothing to query
- if schema_diff is not None and not schema_diff:
- return schema
-
- if schema_diff:
- log.info("Loading schema from DB", schema_to_update=schema_diff.to_list())
-
- for node_type in list(filters.keys()):
- filter_value = {
- "namespace__values": list(
- {parse_node_kind(item).namespace for item in getattr(schema_diff, node_type)}
- ),
- "name__values": list({parse_node_kind(item).name for item in getattr(schema_diff, node_type)}),
- }
-
- if filter_value["namespace__values"]:
- filters[node_type] = filter_value
- has_filters = True
-
- if not has_filters or filters["generics"]:
- generic_schema = self.get(name="SchemaGeneric", branch=branch)
- for schema_node in await self.query(
- schema=generic_schema,
- branch=branch,
- at=at,
- filters=filters["generics"],
- prefetch_relationships=True,
- db=db,
- ):
- kind = f"{schema_node.namespace.value}{schema_node.name.value}"
- schema.set(
- name=kind,
- schema=await self.convert_generic_schema_to_schema(schema_node=schema_node, db=db),
- )
-
- if not has_filters or filters["nodes"]:
- node_schema = self.get(name="SchemaNode", branch=branch)
- for schema_node in await self.query(
- schema=node_schema, branch=branch, at=at, filters=filters["nodes"], prefetch_relationships=True, db=db
- ):
- kind = f"{schema_node.namespace.value}{schema_node.name.value}"
- schema.set(
- name=kind,
- schema=await self.convert_node_schema_to_schema(schema_node=schema_node, db=db),
- )
-
- schema.process(validate_schema=validate_schema)
-
- return schema
-
- @classmethod
- async def _prepare_node_data(cls, schema_node: Node, db: InfrahubDatabase) -> dict[str, Any]:
- node_data = {"id": schema_node.id}
-
- # First pull all the local attributes at the top level, then convert all the local relationships
- # for a standard node_schema, the relationships will be attributes and relationships
- for attr_name in schema_node._attributes:
- attr = getattr(schema_node, attr_name)
- node_data[attr_name] = attr.get_value()
-
- for rel_name in schema_node._relationships:
- if rel_name not in node_data:
- if rel_name == "profiles":
- continue
- node_data[rel_name] = []
-
- rm = getattr(schema_node, rel_name)
- for rel in await rm.get(db=db):
- item = await rel.get_peer(db=db)
- item_data = {"id": item.id}
- for item_name in item._attributes:
- item_attr = getattr(item, item_name)
- item_data[item_name] = item_attr.get_value()
-
- node_data[rel_name].append(item_data)
- return node_data
-
- @classmethod
- async def convert_node_schema_to_schema(cls, schema_node: Node, db: InfrahubDatabase) -> NodeSchema:
- """Convert a schema_node object loaded from the database into NodeSchema object."""
- node_data = await cls._prepare_node_data(schema_node=schema_node, db=db)
- return NodeSchema(**node_data)
-
- @classmethod
- async def convert_generic_schema_to_schema(cls, schema_node: Node, db: InfrahubDatabase) -> GenericSchema:
- """Convert a schema_node object loaded from the database into GenericSchema object."""
- node_data = await cls._prepare_node_data(schema_node=schema_node, db=db)
- return GenericSchema(**node_data)
diff --git a/backend/infrahub/core/task/user_task.py b/backend/infrahub/core/task/user_task.py
index 034da5c049..a2fa6de467 100644
--- a/backend/infrahub/core/task/user_task.py
+++ b/backend/infrahub/core/task/user_task.py
@@ -18,7 +18,7 @@
from infrahub.core.protocols import CoreGenericAccount
from infrahub.database import InfrahubDatabase
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
from infrahub.services.protocols import InfrahubLogger
diff --git a/backend/infrahub/core/utils.py b/backend/infrahub/core/utils.py
index 8befab1a6e..239d542944 100644
--- a/backend/infrahub/core/utils.py
+++ b/backend/infrahub/core/utils.py
@@ -11,6 +11,7 @@
from infrahub.core.timestamp import Timestamp
if TYPE_CHECKING:
+ from neo4j import Record
from neo4j.graph import Node as Neo4jNode
from infrahub.database import InfrahubDatabase
@@ -25,7 +26,7 @@ async def add_relationship(
branch_level: Optional[int] = None,
at: Optional[Timestamp] = None,
status=RelationshipStatus.ACTIVE,
-):
+) -> Record | None:
create_rel_query = """
MATCH (s) WHERE %(id_func)s(s) = $src_node_id
MATCH (d) WHERE %(id_func)s(d) = $dst_node_id
@@ -51,7 +52,7 @@ async def add_relationship(
return results[0][0]
-async def delete_all_relationships_for_branch(branch_name: str, db: InfrahubDatabase):
+async def delete_all_relationships_for_branch(branch_name: str, db: InfrahubDatabase) -> None:
query = """
MATCH ()-[r { branch: $branch_name }]-() DELETE r
"""
@@ -60,7 +61,7 @@ async def delete_all_relationships_for_branch(branch_name: str, db: InfrahubData
await db.execute_query(query=query, params=params, name="delete_all_relationships_for_branch")
-async def update_relationships_to(ids: list[str], db: InfrahubDatabase, to: Timestamp = None):
+async def update_relationships_to(ids: list[str], db: InfrahubDatabase, to: Timestamp = None) -> list[Record] | None:
"""Update the "to" field on one or multiple relationships."""
if not ids:
return None
@@ -86,7 +87,7 @@ async def get_paths_between_nodes(
relationships: Optional[list[str]] = None,
max_length: Optional[int] = None,
print_query=False,
-):
+) -> list[Record]:
"""Return all paths between 2 nodes."""
length_limit = f"..{max_length}" if max_length else ""
@@ -154,7 +155,7 @@ async def count_nodes(db: InfrahubDatabase, label: Optional[str] = None) -> int:
return result[0][0]
-async def delete_all_nodes(db: InfrahubDatabase):
+async def delete_all_nodes(db: InfrahubDatabase) -> list[Record]:
query = """
MATCH (n)
DETACH DELETE n
@@ -210,7 +211,7 @@ class _NewClass:
_all_vars = set(dir(_OldClass) + dir(_NewClass))
-def props(x):
+def props(x) -> dict[str, Any]:
return {key: vars(x).get(key, getattr(x, key)) for key in dir(x) if key not in _all_vars}
@@ -254,5 +255,5 @@ def __init_subclass__(cls, **meta_options):
super_class.__init_subclass_with_meta__(**options)
@classmethod
- def __init_subclass_with_meta__(cls, **meta_options):
+ def __init_subclass_with_meta__(cls, **meta_options) -> None:
"""This method just terminates the super() chain"""
diff --git a/backend/infrahub/core/validators/attribute/unique.py b/backend/infrahub/core/validators/attribute/unique.py
index d77ea4e4c6..793db6a62c 100644
--- a/backend/infrahub/core/validators/attribute/unique.py
+++ b/backend/infrahub/core/validators/attribute/unique.py
@@ -91,7 +91,7 @@ async def get_paths(self) -> GroupedDataPaths:
class AttributeUniquenessChecker(ConstraintCheckerInterface):
query_classes = [AttributeUniqueUpdateValidatorQuery]
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]):
+ def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]) -> None:
self.db = db
self.branch = branch
diff --git a/backend/infrahub/core/validators/checker.py b/backend/infrahub/core/validators/checker.py
index ea4dd300b5..1a7d3d1034 100644
--- a/backend/infrahub/core/validators/checker.py
+++ b/backend/infrahub/core/validators/checker.py
@@ -8,7 +8,7 @@
if TYPE_CHECKING:
from infrahub.core.branch import Branch
from infrahub.core.models import SchemaUpdateConstraintInfo
- from infrahub.core.schema_manager import SchemaBranch
+ from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.message_bus.messages.schema_validator_path import SchemaValidatorPathResponse
from infrahub.services import InfrahubServices
diff --git a/backend/infrahub/core/validators/determiner.py b/backend/infrahub/core/validators/determiner.py
index 305db13a65..e3447c9797 100644
--- a/backend/infrahub/core/validators/determiner.py
+++ b/backend/infrahub/core/validators/determiner.py
@@ -10,7 +10,7 @@
from infrahub.core.path import SchemaPath
from infrahub.core.schema import AttributeSchema, MainSchemaTypes
from infrahub.core.schema.relationship_schema import RelationshipSchema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.validators import CONSTRAINT_VALIDATOR_MAP
from infrahub.log import get_logger
@@ -18,7 +18,7 @@
class ConstraintValidatorDeterminer:
- def __init__(self, schema_branch: SchemaBranch):
+ def __init__(self, schema_branch: SchemaBranch) -> None:
self.schema_branch = schema_branch
self._node_diffs_by_kind: dict[str, NodeDiff] = defaultdict(list)
self._attribute_element_map: dict[str, dict[str, list[NodeDiff]]] = {}
diff --git a/backend/infrahub/core/validators/interface.py b/backend/infrahub/core/validators/interface.py
index 02db3577bd..16aa5fbe53 100644
--- a/backend/infrahub/core/validators/interface.py
+++ b/backend/infrahub/core/validators/interface.py
@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
from typing import List
-from infrahub.core.path import GroupedDataPaths # noqa: TCH001
+from infrahub.core.path import GroupedDataPaths
from .model import SchemaConstraintValidatorRequest
diff --git a/sync/examples/infrahub_to_peering-manager/peeringmanager/__init__.py b/backend/infrahub/core/validators/models/__init__.py
similarity index 100%
rename from sync/examples/infrahub_to_peering-manager/peeringmanager/__init__.py
rename to backend/infrahub/core/validators/models/__init__.py
diff --git a/backend/infrahub/core/validators/models/validate_migration.py b/backend/infrahub/core/validators/models/validate_migration.py
new file mode 100644
index 0000000000..b6d61cc0a8
--- /dev/null
+++ b/backend/infrahub/core/validators/models/validate_migration.py
@@ -0,0 +1,14 @@
+from pydantic import BaseModel, ConfigDict
+
+from infrahub.core.branch import Branch
+from infrahub.core.models import SchemaUpdateConstraintInfo
+from infrahub.core.schema.schema_branch import SchemaBranch
+
+
+class SchemaValidateMigrationData(BaseModel):
+ model_config = ConfigDict(
+ arbitrary_types_allowed=True, json_encoders={SchemaBranch: SchemaBranch.to_dict_schema_object}
+ )
+ branch: Branch
+ schema_branch: SchemaBranch
+ constraints: list[SchemaUpdateConstraintInfo]
diff --git a/backend/infrahub/core/validators/models/violation.py b/backend/infrahub/core/validators/models/violation.py
new file mode 100644
index 0000000000..510eebd6dd
--- /dev/null
+++ b/backend/infrahub/core/validators/models/violation.py
@@ -0,0 +1,22 @@
+from typing import Union
+
+from pydantic import BaseModel, Field
+
+from infrahub.core.branch import Branch
+from infrahub.core.path import SchemaPath
+from infrahub.core.schema import GenericSchema, NodeSchema
+
+
+class SchemaConstraintValidatorRequest(BaseModel):
+ branch: Branch = Field(..., description="The name of the branch to target")
+ constraint_name: str = Field(..., description="The name of the constraint to validate")
+ node_schema: Union[NodeSchema, GenericSchema] = Field(..., description="Schema of Node or Generic to validate")
+ schema_path: SchemaPath = Field(..., description="SchemaPath to the element of the schema to validate")
+
+
+class SchemaViolation(BaseModel):
+ node_id: str
+ node_kind: str
+ display_label: str
+ full_display_label: str
+ message: str = ""
diff --git a/backend/infrahub/core/validators/node/generate_profile.py b/backend/infrahub/core/validators/node/generate_profile.py
index 1784e65eb0..7181508ed6 100644
--- a/backend/infrahub/core/validators/node/generate_profile.py
+++ b/backend/infrahub/core/validators/node/generate_profile.py
@@ -24,7 +24,7 @@ def __init__(
self,
*args: Any,
**kwargs: Any,
- ):
+ ) -> None:
super().__init__(*args, **kwargs)
self.profile_kind = f"Profile{self.node_schema.kind}"
@@ -61,7 +61,7 @@ async def get_paths(self) -> GroupedDataPaths:
class NodeGenerateProfileChecker(ConstraintCheckerInterface):
query_classes = [NodeGenerateProfileValidatorQuery]
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]):
+ def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]) -> None:
self.db = db
self.branch = branch
diff --git a/backend/infrahub/core/validators/node/hierarchy.py b/backend/infrahub/core/validators/node/hierarchy.py
index 4411b258d0..a95a7c8f66 100644
--- a/backend/infrahub/core/validators/node/hierarchy.py
+++ b/backend/infrahub/core/validators/node/hierarchy.py
@@ -26,7 +26,7 @@ def __init__(
check_children: bool = False,
check_parent: bool = False,
**kwargs: Any,
- ):
+ ) -> None:
self.check_children = check_children
self.check_parent = check_parent
super().__init__(**kwargs)
@@ -142,7 +142,7 @@ async def get_paths(self) -> GroupedDataPaths:
class NodeHierarchyChecker(ConstraintCheckerInterface):
query_classes = [NodeHierarchyUpdateValidatorQuery]
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]):
+ def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]) -> None:
self.db = db
self.branch = branch
diff --git a/backend/infrahub/core/validators/node/inherit_from.py b/backend/infrahub/core/validators/node/inherit_from.py
index c5f99dec8c..5ad49b093c 100644
--- a/backend/infrahub/core/validators/node/inherit_from.py
+++ b/backend/infrahub/core/validators/node/inherit_from.py
@@ -18,7 +18,7 @@
class NodeInheritFromChecker(ConstraintCheckerInterface):
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]):
+ def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]) -> None:
self.db = db
self.branch = branch
diff --git a/backend/infrahub/core/validators/relationship/count.py b/backend/infrahub/core/validators/relationship/count.py
index 30c477205a..85ab9f1d29 100644
--- a/backend/infrahub/core/validators/relationship/count.py
+++ b/backend/infrahub/core/validators/relationship/count.py
@@ -25,7 +25,7 @@ def __init__(
min_count_override: Optional[int] = None,
max_count_override: Optional[int] = None,
**kwargs: Any,
- ):
+ ) -> None:
self.min_count_override = min_count_override
self.max_count_override = max_count_override
super().__init__(**kwargs)
@@ -146,7 +146,7 @@ async def get_paths(self) -> GroupedDataPaths:
class RelationshipCountChecker(ConstraintCheckerInterface):
query_classes = [RelationshipCountUpdateValidatorQuery]
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]):
+ def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]) -> None:
self.db = db
self.branch = branch
diff --git a/backend/infrahub/core/validators/relationship/optional.py b/backend/infrahub/core/validators/relationship/optional.py
index 4b5aaa7b57..24dacb50a6 100644
--- a/backend/infrahub/core/validators/relationship/optional.py
+++ b/backend/infrahub/core/validators/relationship/optional.py
@@ -86,7 +86,7 @@ async def get_paths(self) -> GroupedDataPaths:
class RelationshipOptionalChecker(ConstraintCheckerInterface):
query_classes = [RelationshipOptionalUpdateValidatorQuery]
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]):
+ def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]) -> None:
self.db = db
self.branch = branch
diff --git a/backend/infrahub/core/validators/relationship/peer.py b/backend/infrahub/core/validators/relationship/peer.py
index 885f1a9589..7ff63d069f 100644
--- a/backend/infrahub/core/validators/relationship/peer.py
+++ b/backend/infrahub/core/validators/relationship/peer.py
@@ -110,7 +110,7 @@ async def get_paths(self) -> GroupedDataPaths:
class RelationshipPeerChecker(ConstraintCheckerInterface):
query_classes = [RelationshipPeerUpdateValidatorQuery]
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]):
+ def __init__(self, db: InfrahubDatabase, branch: Optional[Branch]) -> None:
self.db = db
self.branch = branch
diff --git a/backend/infrahub/core/validators/shared.py b/backend/infrahub/core/validators/shared.py
index 543ff3efb3..2d1f91bd22 100644
--- a/backend/infrahub/core/validators/shared.py
+++ b/backend/infrahub/core/validators/shared.py
@@ -15,7 +15,7 @@ def __init__(
node_schema: Union[NodeSchema, GenericSchema],
schema_path: SchemaPath,
**kwargs: Any,
- ):
+ ) -> None:
self.node_schema = node_schema
self.schema_path = schema_path
super().__init__(**kwargs)
diff --git a/backend/infrahub/core/validators/tasks.py b/backend/infrahub/core/validators/tasks.py
new file mode 100644
index 0000000000..8ba163eaf0
--- /dev/null
+++ b/backend/infrahub/core/validators/tasks.py
@@ -0,0 +1,44 @@
+from __future__ import annotations
+
+from infrahub_sdk.batch import InfrahubBatch
+from prefect import flow
+
+from infrahub.message_bus.messages.schema_validator_path import (
+ SchemaValidatorPathData,
+)
+from infrahub.message_bus.operations.schema.validator import schema_path_validate
+from infrahub.services import services
+
+from .models.validate_migration import SchemaValidateMigrationData # noqa: TCH001
+
+
+@flow
+async def schema_validate_migrations(message: SchemaValidateMigrationData) -> list[str]:
+ batch = InfrahubBatch(return_exceptions=True)
+ error_messages: list[str] = []
+ service = services.service
+
+ if not message.constraints:
+ return error_messages
+
+ for constraint in message.constraints:
+ service.log.info(
+ f"Preparing validator for constraint {constraint.constraint_name!r} ({constraint.routing_key})",
+ branch=message.branch.name,
+ constraint_name=constraint.constraint_name,
+ routing_key=constraint.routing_key,
+ )
+
+ msg = SchemaValidatorPathData(
+ branch=message.branch,
+ constraint_name=constraint.constraint_name,
+ node_schema=message.schema_branch.get(name=constraint.path.schema_kind),
+ schema_path=constraint.path,
+ )
+ batch.add(task=schema_path_validate, message=msg)
+
+ async for _, result in batch.execute():
+ for violation in result.violations:
+ error_messages.append(violation.message)
+
+ return error_messages
diff --git a/backend/infrahub/core/validators/uniqueness/checker.py b/backend/infrahub/core/validators/uniqueness/checker.py
index 8bb058d81e..0a06e7afb2 100644
--- a/backend/infrahub/core/validators/uniqueness/checker.py
+++ b/backend/infrahub/core/validators/uniqueness/checker.py
@@ -46,7 +46,7 @@ def get_attribute_path_from_string(
class UniquenessChecker(ConstraintCheckerInterface):
def __init__(
self, db: InfrahubDatabase, branch: Optional[Union[Branch, str]] = None, max_concurrent_execution: int = 5
- ):
+ ) -> None:
self.db = db
self.branch = branch
self.semaphore = asyncio.Semaphore(max_concurrent_execution)
diff --git a/backend/infrahub/core/validators/uniqueness/index.py b/backend/infrahub/core/validators/uniqueness/index.py
index 5465040225..dc79573fea 100644
--- a/backend/infrahub/core/validators/uniqueness/index.py
+++ b/backend/infrahub/core/validators/uniqueness/index.py
@@ -31,7 +31,7 @@ def __hash__(self) -> int:
class UniquenessQueryResultsIndex:
- def __init__(self, query_results: Iterable[QueryResult], exclude_node_ids: Optional[set[str]] = None):
+ def __init__(self, query_results: Iterable[QueryResult], exclude_node_ids: Optional[set[str]] = None) -> None:
self._relationship_index: dict[str, dict[str, set[str]]] = {}
self._attribute_index: dict[str, dict[Any, set[str]]] = {}
self._node_index: dict[str, dict[str, Any]] = {}
diff --git a/backend/infrahub/core/validators/uniqueness/query.py b/backend/infrahub/core/validators/uniqueness/query.py
index d709fb50f3..c7ab8fbf11 100644
--- a/backend/infrahub/core/validators/uniqueness/query.py
+++ b/backend/infrahub/core/validators/uniqueness/query.py
@@ -21,7 +21,7 @@ def __init__(
query_request: NodeUniquenessQueryRequest,
min_count_required: int = 1,
**kwargs: Any,
- ):
+ ) -> None:
self.query_request = query_request
self.min_count_required = min_count_required
super().__init__(**kwargs)
diff --git a/backend/infrahub/database/__init__.py b/backend/infrahub/database/__init__.py
index b5e59977cd..e49418909f 100644
--- a/backend/infrahub/database/__init__.py
+++ b/backend/infrahub/database/__init__.py
@@ -2,7 +2,7 @@
import asyncio
import random
-from typing import TYPE_CHECKING, Any, Optional, Union
+from typing import TYPE_CHECKING, Any, Callable, Coroutine, Optional, TypeVar, Union
from neo4j import (
READ_ACCESS,
@@ -40,11 +40,12 @@
from infrahub.core.branch import Branch
from infrahub.core.schema import MainSchemaTypes, NodeSchema
- from infrahub.core.schema_manager import SchemaBranch
+ from infrahub.core.schema.schema_branch import SchemaBranch
from .manager import DatabaseManager
validated_database = {}
+R = TypeVar("R")
log = get_logger()
@@ -70,7 +71,7 @@ def get_branch_name(branch: Optional[Union[Branch, str]] = None) -> str:
class DatabaseSchemaManager:
- def __init__(self, db: InfrahubDatabase):
+ def __init__(self, db: InfrahubDatabase) -> None:
self._db = db
def get(self, name: str, branch: Optional[Union[Branch, str]] = None, duplicate: bool = True) -> MainSchemaTypes:
@@ -133,7 +134,7 @@ def __init__(
session: Optional[AsyncSession] = None,
session_mode: InfrahubDatabaseSessionMode = InfrahubDatabaseSessionMode.WRITE,
transaction: Optional[AsyncTransaction] = None,
- ):
+ ) -> None:
self._mode: InfrahubDatabaseMode = mode
self._driver: AsyncDriver = driver
self._session: Optional[AsyncSession] = session
@@ -400,7 +401,7 @@ async def get_db(retry: int = 0) -> AsyncDriver:
encrypted=config.SETTINGS.database.tls_enabled,
trusted_certificates=trusted_certificates,
notifications_disabled_categories=[NotificationDisabledCategory.UNRECOGNIZED],
- notifications_min_severity=NotificationMinimumSeverity.OFF,
+ notifications_min_severity=NotificationMinimumSeverity.WARNING,
)
if config.SETTINGS.database.database_name not in validated_database:
@@ -411,9 +412,12 @@ async def get_db(retry: int = 0) -> AsyncDriver:
return driver
-def retry_db_transaction(name: str):
- def func_wrapper(func):
- async def wrapper(*args, **kwargs):
+def retry_db_transaction(
+ name: str,
+) -> Callable[[Callable[..., Coroutine[Any, Any, R]]], Callable[..., Coroutine[Any, Any, R]]]:
+ def func_wrapper(func: Callable[..., Coroutine[Any, Any, R]]) -> Callable[..., Coroutine[Any, Any, R]]:
+ async def wrapper(*args: Any, **kwargs: Any) -> R:
+ error = Exception()
for attempt in range(1, config.SETTINGS.database.retry_limit + 1):
try:
return await func(*args, **kwargs)
@@ -423,11 +427,13 @@ async def wrapper(*args, **kwargs):
f"Retrying database transaction, attempt {attempt}/{config.SETTINGS.database.retry_limit}",
retry_time=retry_time,
)
- log.debug("database transaction failed", message=exc.message)
+ log.debug("Database transaction failed", message=exc.message)
TRANSACTION_RETRIES.labels(name).inc()
await asyncio.sleep(retry_time)
if attempt == config.SETTINGS.database.retry_limit:
- raise
+ error = exc
+ break
+ raise error
return wrapper
diff --git a/backend/infrahub/database/index.py b/backend/infrahub/database/index.py
index 9120a64341..3f0ec27718 100644
--- a/backend/infrahub/database/index.py
+++ b/backend/infrahub/database/index.py
@@ -33,7 +33,7 @@ def get_drop_query(self) -> str:
class IndexManagerBase(ABC):
- def __init__(self, db: InfrahubDatabase):
+ def __init__(self, db: InfrahubDatabase) -> None:
self.db = db
self.nodes: list[IndexItem] = []
diff --git a/backend/infrahub/database/manager.py b/backend/infrahub/database/manager.py
index 7b70a1efaf..321c07c1b9 100644
--- a/backend/infrahub/database/manager.py
+++ b/backend/infrahub/database/manager.py
@@ -11,5 +11,5 @@
class DatabaseManager(ABC):
index: IndexManagerBase
- def __init__(self, db: InfrahubDatabase):
+ def __init__(self, db: InfrahubDatabase) -> None:
self.db = db
diff --git a/backend/infrahub/database/memgraph.py b/backend/infrahub/database/memgraph.py
index 1922178151..0a9509478c 100644
--- a/backend/infrahub/database/memgraph.py
+++ b/backend/infrahub/database/memgraph.py
@@ -54,6 +54,6 @@ async def list(self) -> list[IndexInfo]:
class DatabaseManagerMemgraph(DatabaseManager):
- def __init__(self, db: InfrahubDatabase):
+ def __init__(self, db: InfrahubDatabase) -> None:
super().__init__(db=db)
self.index = IndexManagerMemgraph(db=db)
diff --git a/backend/infrahub/database/neo4j.py b/backend/infrahub/database/neo4j.py
index 45170988ce..8e08bd4279 100644
--- a/backend/infrahub/database/neo4j.py
+++ b/backend/infrahub/database/neo4j.py
@@ -69,6 +69,6 @@ async def list(self) -> list[IndexInfo]:
class DatabaseManagerNeo4j(DatabaseManager):
- def __init__(self, db: InfrahubDatabase):
+ def __init__(self, db: InfrahubDatabase) -> None:
super().__init__(db=db)
self.index = IndexManagerNeo4j(db=db)
diff --git a/backend/infrahub/events/__init__.py b/backend/infrahub/events/__init__.py
new file mode 100644
index 0000000000..857036ba61
--- /dev/null
+++ b/backend/infrahub/events/__init__.py
@@ -0,0 +1,4 @@
+from .models import EventMeta, InfrahubEvent
+from .node_action import NodeMutatedEvent
+
+__all__ = ["EventMeta", "InfrahubEvent", "NodeMutatedEvent"]
diff --git a/backend/infrahub/events/constants.py b/backend/infrahub/events/constants.py
new file mode 100644
index 0000000000..9c5c628d46
--- /dev/null
+++ b/backend/infrahub/events/constants.py
@@ -0,0 +1 @@
+EVENT_NAMESPACE = "infrahub"
diff --git a/backend/infrahub/events/models.py b/backend/infrahub/events/models.py
new file mode 100644
index 0000000000..1717fc97b8
--- /dev/null
+++ b/backend/infrahub/events/models.py
@@ -0,0 +1,93 @@
+from typing import Any
+
+from pydantic import BaseModel, Field
+
+from infrahub.message_bus import InfrahubMessage, Meta
+
+from .constants import EVENT_NAMESPACE
+
+
+class EventMeta(BaseModel):
+ request_id: str = ""
+ account_id: str = ""
+ initiator_id: str | None = Field(
+ default=None, description="The worker identity of the initial sender of this message"
+ )
+
+
+class InfrahubEvent(BaseModel):
+ meta: EventMeta | None = None
+
+ def get_event_namespace(self) -> str:
+ return EVENT_NAMESPACE
+
+ def get_name(self) -> str:
+ return f"{self.get_event_namespace()}.unknown"
+
+ def get_resource(self) -> dict[str, str]:
+ raise NotImplementedError
+
+ def get_message(self) -> InfrahubMessage:
+ raise NotImplementedError
+
+ def get_related(self) -> list[dict[str, str]]:
+ related: list[dict[str, str]] = []
+
+ if not self.meta:
+ return related
+
+ if self.meta.account_id:
+ related.append(
+ {
+ "prefect.resource.id": f"infrahub.account.{self.meta.account_id}",
+ "prefect.resource.role": "account",
+ }
+ )
+
+ if self.meta.request_id:
+ related.append(
+ {
+ "prefect.resource.id": f"infrahub.request.{self.meta.request_id}",
+ "prefect.resource.role": "request",
+ }
+ )
+
+ if self.meta.initiator_id:
+ related.append(
+ {
+ "prefect.resource.id": f"infrahub.source.{self.meta.initiator_id}",
+ "prefect.resource.role": "event_source",
+ }
+ )
+
+ return related
+
+ def get_payload(self) -> dict[str, Any]:
+ return {}
+
+ def get_message_meta(self) -> Meta:
+ meta = Meta()
+ if not self.meta:
+ return meta
+
+ if self.meta.initiator_id:
+ meta.initiator_id = self.meta.initiator_id
+ if self.meta.request_id:
+ meta.initiator_id = self.meta.request_id
+
+ return meta
+
+
+class InfrahubBranchEvent(InfrahubEvent): # pylint: disable=abstract-method
+ branch: str = Field(..., description="The branch on which the event happend")
+
+ def get_related(self) -> list[dict[str, str]]:
+ related = super().get_related()
+ related.append(
+ {
+ "prefect.resource.id": "infrahub.branch",
+ "prefect.resource.name": self.branch,
+ "prefect.resource.role": "branch",
+ }
+ )
+ return related
diff --git a/backend/infrahub/events/node_action.py b/backend/infrahub/events/node_action.py
new file mode 100644
index 0000000000..ad40f664d9
--- /dev/null
+++ b/backend/infrahub/events/node_action.py
@@ -0,0 +1,40 @@
+from typing import Any
+
+from pydantic import Field
+
+from infrahub.core.constants import MutationAction
+from infrahub.message_bus.messages.event_node_mutated import EventNodeMutated
+
+from .models import InfrahubBranchEvent
+
+
+class NodeMutatedEvent(InfrahubBranchEvent):
+ """Event generated when a node has been mutated"""
+
+ kind: str = Field(..., description="The type of object modified")
+ node_id: str = Field(..., description="The ID of the mutated node")
+ action: MutationAction = Field(..., description="The action taken on the node")
+ data: dict[str, Any] = Field(..., description="Data on modified object")
+
+ def get_name(self) -> str:
+ return f"{self.get_event_namespace()}.node.{self.action.value}"
+
+ def get_resource(self) -> dict[str, str]:
+ return {
+ "prefect.resource.id": f"infrahub.node.{self.node_id}",
+ "infrahub.node.kind": self.kind,
+ "infrahub.node.action": self.action.value,
+ }
+
+ def get_payload(self) -> dict[str, Any]:
+ return self.data
+
+ def get_message(self) -> EventNodeMutated:
+ return EventNodeMutated(
+ branch=self.branch,
+ kind=self.kind,
+ node_id=self.node_id,
+ action=self.action.value,
+ data=self.data,
+ meta=self.get_message_meta(),
+ )
diff --git a/backend/infrahub/exceptions.py b/backend/infrahub/exceptions.py
index 2451a91d6e..c5b5b2d3a9 100644
--- a/backend/infrahub/exceptions.py
+++ b/backend/infrahub/exceptions.py
@@ -20,7 +20,7 @@ def api_response(self) -> dict[str, Any]:
class RPCError(Error):
HTTP_CODE: int = 502
- def __init__(self, message: str):
+ def __init__(self, message: str) -> None:
self.message = message
@@ -32,7 +32,7 @@ class DatabaseError(Error):
HTTP_CODE: int = 503
DESCRIPTION = "Database unavailable"
- def __init__(self, message: str):
+ def __init__(self, message: str) -> None:
self.message = message
super().__init__(self.message)
@@ -44,12 +44,12 @@ class LockError(Error):
class GraphQLQueryError(Error):
HTTP_CODE = 502
- def __init__(self, errors: list):
+ def __init__(self, errors: list) -> None:
self.errors = errors
class RepositoryError(Error):
- def __init__(self, identifier: str, message: Optional[str] = None):
+ def __init__(self, identifier: str, message: Optional[str] = None) -> None:
self.identifier = identifier
self.message = message or f"An error occurred with GitRepository '{identifier}'."
super().__init__(self.message)
@@ -58,7 +58,7 @@ def __init__(self, identifier: str, message: Optional[str] = None):
class CommitNotFoundError(Error):
HTTP_CODE: int = 400
- def __init__(self, identifier: str, commit: str, message: Optional[str] = None):
+ def __init__(self, identifier: str, commit: str, message: Optional[str] = None) -> None:
self.identifier = identifier
self.commit = commit
self.message = message or f"Commit {commit} not found with GitRepository '{identifier}'."
@@ -68,7 +68,7 @@ def __init__(self, identifier: str, commit: str, message: Optional[str] = None):
class DataTypeNotFoundError(Error):
HTTP_CODE: int = 400
- def __init__(self, name: str, message: Optional[str] = None):
+ def __init__(self, name: str, message: Optional[str] = None) -> None:
self.name = name
self.message = message or f"Unable to find the DataType '{name}'."
super().__init__(self.message)
@@ -77,7 +77,7 @@ def __init__(self, name: str, message: Optional[str] = None):
class RepositoryFileNotFoundError(Error):
HTTP_CODE: int = 404
- def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None):
+ def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None) -> None:
self.repository_name = repository_name
self.location = location
self.commit = commit
@@ -88,7 +88,7 @@ def __init__(self, repository_name: str, location: str, commit: str, message: Op
class FileOutOfRepositoryError(Error):
HTTP_CODE: int = 403
- def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None):
+ def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None) -> None:
self.repository_name = repository_name
self.location = location
self.commit = commit
@@ -97,7 +97,7 @@ def __init__(self, repository_name: str, location: str, commit: str, message: Op
class TransformError(Error):
- def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None):
+ def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None) -> None:
self.repository_name = repository_name
self.location = location
self.commit = commit
@@ -110,7 +110,7 @@ def __init__(self, repository_name: str, location: str, commit: str, message: Op
class CheckError(Error):
def __init__(
self, repository_name: str, location: str, class_name: str, commit: str, message: Optional[str] = None
- ):
+ ) -> None:
self.repository_name = repository_name
self.location = location
self.commit = commit
@@ -123,7 +123,7 @@ def __init__(
class TransformNotFoundError(TransformError):
- def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None):
+ def __init__(self, repository_name: str, location: str, commit: str, message: Optional[str] = None) -> None:
self.message = (
message or f"Unable to locate the transform function at '{repository_name}::{commit}::{location}'."
)
@@ -133,7 +133,7 @@ def __init__(self, repository_name: str, location: str, commit: str, message: Op
class BranchNotFoundError(Error):
HTTP_CODE: int = 400
- def __init__(self, identifier: str, message: Optional[str] = None):
+ def __init__(self, identifier: str, message: Optional[str] = None) -> None:
self.identifier = identifier
self.message = message or f"Branch: {identifier} not found."
super().__init__(self.message)
@@ -144,7 +144,7 @@ class NodeNotFoundError(Error):
def __init__(
self, node_type: str, identifier: str, branch_name: Optional[str] = None, message: Optional[str] = None
- ):
+ ) -> None:
self.node_type = node_type
self.identifier = identifier
self.branch_name = branch_name
@@ -161,7 +161,7 @@ def __str__(self) -> str:
class ResourceNotFoundError(Error):
HTTP_CODE: int = 404
- def __init__(self, message: Optional[str] = None):
+ def __init__(self, message: Optional[str] = None) -> None:
self.message = message or "The requested resource was not found"
super().__init__(self.message)
@@ -170,7 +170,7 @@ class AuthorizationError(Error):
HTTP_CODE: int = 401
message: str = "Access to the requested resource was denied"
- def __init__(self, message: Optional[str] = None):
+ def __init__(self, message: Optional[str] = None) -> None:
self.message = message or self.message
super().__init__(self.message)
@@ -179,7 +179,7 @@ class PermissionDeniedError(Error):
HTTP_CODE: int = 403
message: str = "The requested operation was not authorized"
- def __init__(self, message: Optional[str] = None):
+ def __init__(self, message: Optional[str] = None) -> None:
self.message = message or self.message
super().__init__(self.message)
@@ -188,7 +188,7 @@ class ProcessingError(Error):
HTTP_CODE: int = 400
message: str = "Unable to process the request"
- def __init__(self, message: Optional[str] = None):
+ def __init__(self, message: Optional[str] = None) -> None:
self.message = message or self.message
super().__init__(self.message)
@@ -197,7 +197,7 @@ class PoolExhaustedError(Error):
HTTP_CODE: int = 409
message: str = "No more resources available in the pool"
- def __init__(self, message: Optional[str] = None):
+ def __init__(self, message: Optional[str] = None) -> None:
self.message = message or self.message
super().__init__(self.message)
@@ -205,7 +205,7 @@ def __init__(self, message: Optional[str] = None):
class SchemaNotFoundError(Error):
HTTP_CODE: int = 422
- def __init__(self, branch_name: str, identifier: str, message: Optional[str] = None):
+ def __init__(self, branch_name: str, identifier: str, message: Optional[str] = None) -> None:
self.branch_name = branch_name
self.identifier = identifier
self.message = message or f"Unable to find the schema {identifier} in the database."
@@ -219,7 +219,7 @@ def __str__(self) -> str:
class QueryError(Error):
- def __init__(self, query: str, params: dict, message: str = "Unable to execute the CYPHER query."):
+ def __init__(self, query: str, params: dict, message: str = "Unable to execute the CYPHER query.") -> None:
self.query = query
self.params = params
@@ -237,21 +237,28 @@ def __str__(self) -> str:
class QueryValidationError(Error):
HTTP_CODE = 400
- def __init__(self, message: str):
+ def __init__(self, message: str) -> None:
+ self.message = message
+
+
+class GatewayError(Error):
+ HTTP_CODE = 502
+
+ def __init__(self, message: str) -> None:
self.message = message
class MigrationError(Error):
HTTP_CODE = 502
- def __init__(self, message: str):
+ def __init__(self, message: str) -> None:
self.message = message
class ValidationError(Error):
HTTP_CODE = 422
- def __init__(self, input_value: Union[str, dict, list]):
+ def __init__(self, input_value: Union[str, dict, list]) -> None:
self.message = ""
self.location = None
self.messages = {}
@@ -285,7 +292,7 @@ def __str__(self) -> str:
class DiffError(Error):
HTTP_CODE = 400
- def __init__(self, message: str):
+ def __init__(self, message: str) -> None:
self.message = message
@@ -293,3 +300,20 @@ class DiffRangeValidationError(DiffError): ...
class DiffFromRequiredOnDefaultBranchError(DiffError): ...
+
+
+class HTTPServerError(Error):
+ """Errors raised when communicating with external HTTP servers"""
+
+ HTTP_CODE = 502
+
+ def __init__(self, message: str) -> None:
+ self.message = message
+
+
+class HTTPServerTimeoutError(HTTPServerError):
+ HTTP_CODE = 504
+
+
+class HTTPServerSSLError(HTTPServerError):
+ HTTP_CODE = 503
diff --git a/backend/infrahub/git/integrator.py b/backend/infrahub/git/integrator.py
index 8f3b807949..c7b199af6d 100644
--- a/backend/infrahub/git/integrator.py
+++ b/backend/infrahub/git/integrator.py
@@ -16,6 +16,16 @@
InfrahubRepositoryConfig,
ValidationError,
)
+from infrahub_sdk.protocols import (
+ CoreArtifact,
+ CoreArtifactDefinition,
+ CoreCheckDefinition,
+ CoreGeneratorDefinition,
+ CoreGraphQLQuery,
+ CoreTransformation,
+ CoreTransformJinja2,
+ CoreTransformPython,
+)
from infrahub_sdk.schema import (
InfrahubCheckDefinitionConfig,
InfrahubGeneratorDefinitionConfig,
@@ -191,7 +201,7 @@ async def import_jinja2_transforms(
transforms_in_graph = {
transform.name.value: transform
for transform in await self.sdk.filters(
- kind=InfrahubKind.TRANSFORMJINJA2, branch=branch_name, repository__ids=[str(self.id)]
+ kind=CoreTransformJinja2, branch=branch_name, repository__ids=[str(self.id)]
)
}
@@ -256,18 +266,18 @@ async def import_jinja2_transforms(
)
await transforms_in_graph[transform_name].delete()
- async def create_jinja2_transform(self, branch_name: str, data: InfrahubRepositoryJinja2) -> InfrahubNode:
+ async def create_jinja2_transform(self, branch_name: str, data: InfrahubRepositoryJinja2) -> CoreTransformJinja2:
schema = await self.sdk.schema.get(kind=InfrahubKind.TRANSFORMJINJA2, branch=branch_name)
create_payload = self.sdk.schema.generate_payload_create(
schema=schema, data=data.payload, source=self.id, is_protected=True
)
- obj = await self.sdk.create(kind=InfrahubKind.TRANSFORMJINJA2, branch=branch_name, **create_payload)
+ obj = await self.sdk.create(kind=CoreTransformJinja2, branch=branch_name, **create_payload)
await obj.save()
return obj
@classmethod
async def compare_jinja2_transform(
- cls, existing_transform: InfrahubNode, local_transform: InfrahubRepositoryJinja2
+ cls, existing_transform: CoreTransformJinja2, local_transform: InfrahubRepositoryJinja2
) -> bool:
# pylint: disable=no-member
if (
@@ -280,7 +290,7 @@ async def compare_jinja2_transform(
return True
async def update_jinja2_transform(
- self, existing_transform: InfrahubNode, local_transform: InfrahubRepositoryJinja2
+ self, existing_transform: CoreTransformJinja2, local_transform: InfrahubRepositoryJinja2
) -> None:
# pylint: disable=no-member
if existing_transform.description.value != local_transform.description:
@@ -303,7 +313,7 @@ async def import_artifact_definitions(
artifact_defs_in_graph = {
artdef.name.value: artdef
- for artdef in await self.sdk.filters(kind=InfrahubKind.ARTIFACTDEFINITION, branch=branch_name)
+ for artdef in await self.sdk.filters(kind=CoreArtifactDefinition, branch=branch_name)
}
local_artifact_defs: dict[str, InfrahubRepositoryArtifactDefinitionConfig] = {}
@@ -364,7 +374,7 @@ async def create_artifact_definition(
@classmethod
async def compare_artifact_definition(
cls,
- existing_artifact_definition: InfrahubNode,
+ existing_artifact_definition: CoreArtifactDefinition,
local_artifact_definition: InfrahubRepositoryArtifactDefinitionConfig,
) -> bool:
# pylint: disable=no-member
@@ -379,7 +389,7 @@ async def compare_artifact_definition(
async def update_artifact_definition(
self,
- existing_artifact_definition: InfrahubNode,
+ existing_artifact_definition: CoreArtifactDefinition,
local_artifact_definition: InfrahubRepositoryArtifactDefinitionConfig,
) -> None:
# pylint: disable=no-member
@@ -533,7 +543,7 @@ async def import_all_graphql_query(
queries_in_graph = {
query.name.value: query
for query in await self.sdk.filters(
- kind=InfrahubKind.GRAPHQLQUERY, branch=branch_name, repository__ids=[str(self.id)]
+ kind=CoreGraphQLQuery, branch=branch_name, repository__ids=[str(self.id)]
)
}
@@ -574,7 +584,7 @@ async def import_all_graphql_query(
)
await graph_query.delete()
- async def create_graphql_query(self, branch_name: str, name: str, query_string: str) -> InfrahubNode:
+ async def create_graphql_query(self, branch_name: str, name: str, query_string: str) -> CoreGraphQLQuery:
data = {"name": name, "query": query_string, "repository": self.id}
schema = await self.sdk.schema.get(kind=InfrahubKind.GRAPHQLQUERY, branch=branch_name)
@@ -584,7 +594,7 @@ async def create_graphql_query(self, branch_name: str, name: str, query_string:
source=self.id,
is_protected=True,
)
- obj = await self.sdk.create(kind=InfrahubKind.GRAPHQLQUERY, branch=branch_name, **create_payload)
+ obj = await self.sdk.create(kind=CoreGraphQLQuery, branch=branch_name, **create_payload)
await obj.save()
return obj
@@ -629,7 +639,7 @@ async def import_python_check_definitions(
check_definition_in_graph = {
check.name.value: check
for check in await self.sdk.filters(
- kind=InfrahubKind.CHECKDEFINITION, branch=branch_name, repository__ids=[str(self.id)]
+ kind=CoreCheckDefinition, branch=branch_name, repository__ids=[str(self.id)]
)
}
@@ -697,7 +707,7 @@ async def import_generator_definitions(
generator_definition_in_graph = {
generator.name.value: generator
for generator in await self.sdk.filters(
- kind=InfrahubKind.GENERATORDEFINITION, branch=branch_name, repository__ids=[str(self.id)]
+ kind=CoreGeneratorDefinition, branch=branch_name, repository__ids=[str(self.id)]
)
}
@@ -744,7 +754,10 @@ async def import_generator_definitions(
await generator_definition_in_graph[generator_name].delete()
async def _generator_requires_update(
- self, generator: InfrahubGeneratorDefinitionConfig, existing_generator: InfrahubNode, branch_name: str
+ self,
+ generator: InfrahubGeneratorDefinitionConfig,
+ existing_generator: CoreGeneratorDefinition,
+ branch_name: str,
) -> bool:
graphql_queries = await self.sdk.filters(
kind=InfrahubKind.GRAPHQLQUERY, branch=branch_name, name__value=generator.query, populate_store=True
@@ -955,7 +968,7 @@ async def _create_generator_definition(
async def _update_generator_definition(
self,
generator: InfrahubGeneratorDefinitionConfig,
- existing_generator: InfrahubNode,
+ existing_generator: CoreGeneratorDefinition,
) -> None:
if existing_generator.query.id != generator.query:
existing_generator.query = {"id": generator.query, "source": str(self.id), "is_protected": True}
@@ -977,7 +990,9 @@ async def _update_generator_definition(
await existing_generator.save()
- async def create_python_check_definition(self, branch_name: str, check: CheckDefinitionInformation) -> InfrahubNode:
+ async def create_python_check_definition(
+ self, branch_name: str, check: CheckDefinitionInformation
+ ) -> CoreCheckDefinition:
data = {
"name": check.name,
"repository": check.repository,
@@ -999,7 +1014,7 @@ async def create_python_check_definition(self, branch_name: str, check: CheckDef
source=self.id,
is_protected=True,
)
- obj = await self.sdk.create(kind=InfrahubKind.CHECKDEFINITION, branch=branch_name, **create_payload)
+ obj = await self.sdk.create(kind=CoreCheckDefinition, branch=branch_name, **create_payload)
await obj.save()
return obj
@@ -1007,7 +1022,7 @@ async def create_python_check_definition(self, branch_name: str, check: CheckDef
async def update_python_check_definition(
self,
check: CheckDefinitionInformation,
- existing_check: InfrahubNode,
+ existing_check: CoreCheckDefinition,
) -> None:
if existing_check.query.id != check.query:
existing_check.query = {"id": check.query, "source": str(self.id), "is_protected": True}
@@ -1025,7 +1040,7 @@ async def update_python_check_definition(
@classmethod
async def compare_python_check_definition(
- cls, check: CheckDefinitionInformation, existing_check: InfrahubNode
+ cls, check: CheckDefinitionInformation, existing_check: CoreCheckDefinition
) -> bool:
"""Compare an existing Python Check Object with a Check Class
and identify if we need to update the object in the database."""
@@ -1040,7 +1055,9 @@ async def compare_python_check_definition(
return False
return True
- async def create_python_transform(self, branch_name: str, transform: TransformPythonInformation) -> InfrahubNode:
+ async def create_python_transform(
+ self, branch_name: str, transform: TransformPythonInformation
+ ) -> CoreTransformPython:
schema = await self.sdk.schema.get(kind=InfrahubKind.TRANSFORMPYTHON, branch=branch_name)
data = {
"name": transform.name,
@@ -1056,12 +1073,12 @@ async def create_python_transform(self, branch_name: str, transform: TransformPy
source=self.id,
is_protected=True,
)
- obj = await self.sdk.create(kind=InfrahubKind.TRANSFORMPYTHON, branch=branch_name, **create_payload)
+ obj = await self.sdk.create(kind=CoreTransformPython, branch=branch_name, **create_payload)
await obj.save()
return obj
async def update_python_transform(
- self, existing_transform: InfrahubNode, local_transform: TransformPythonInformation
+ self, existing_transform: CoreTransformPython, local_transform: TransformPythonInformation
) -> None:
if existing_transform.query.id != local_transform.query:
existing_transform.query = {"id": local_transform.query, "source": str(self.id), "is_protected": True}
@@ -1076,7 +1093,7 @@ async def update_python_transform(
@classmethod
async def compare_python_transform(
- cls, existing_transform: InfrahubNode, local_transform: TransformPythonInformation
+ cls, existing_transform: CoreTransformPython, local_transform: TransformPythonInformation
) -> bool:
if (
existing_transform.query.id != local_transform.query
@@ -1244,11 +1261,11 @@ async def artifact_generate(
self,
branch_name: str,
commit: str,
- artifact: InfrahubNode,
+ artifact: CoreArtifact,
target: InfrahubNode,
- definition: InfrahubNode,
- transformation: InfrahubNode,
- query: InfrahubNode,
+ definition: CoreArtifactDefinition,
+ transformation: CoreTransformation,
+ query: CoreGraphQLQuery,
) -> ArtifactGenerateResult:
variables = target.extract(params=definition.parameters.value)
response = await self.sdk.query_gql_query(
@@ -1298,7 +1315,7 @@ async def artifact_generate(
return ArtifactGenerateResult(changed=True, checksum=checksum, storage_id=storage_id, artifact_id=artifact.id)
async def render_artifact(
- self, artifact: InfrahubNode, message: Union[messages.CheckArtifactCreate, messages.RequestArtifactGenerate]
+ self, artifact: CoreArtifact, message: Union[messages.CheckArtifactCreate, messages.RequestArtifactGenerate]
) -> ArtifactGenerateResult:
response = await self.sdk.query_gql_query(
name=message.query,
diff --git a/backend/infrahub/git_credential/askpass.py b/backend/infrahub/git_credential/askpass.py
index e05aeb8f72..eab658f800 100644
--- a/backend/infrahub/git_credential/askpass.py
+++ b/backend/infrahub/git_credential/askpass.py
@@ -18,7 +18,7 @@
def askpass(
text: Optional[list[str]] = typer.Argument(None),
config_file: str = typer.Option("infrahub.toml", envvar="INFRAHUB_CONFIG"),
-):
+) -> None:
config.SETTINGS.initialize_and_exit(config_file=config_file)
text = text or sys.stdin.read().strip()
diff --git a/backend/infrahub/graphql/__init__.py b/backend/infrahub/graphql/__init__.py
index cf7b144348..e69de29bb2 100644
--- a/backend/infrahub/graphql/__init__.py
+++ b/backend/infrahub/graphql/__init__.py
@@ -1,99 +0,0 @@
-from __future__ import annotations
-
-from dataclasses import dataclass
-from typing import TYPE_CHECKING, Optional, Union
-
-from starlette.background import BackgroundTasks
-
-from infrahub.core import registry
-from infrahub.core.timestamp import Timestamp
-
-from .manager import GraphQLSchemaManager
-
-if TYPE_CHECKING:
- from graphql import GraphQLSchema
- from starlette.requests import HTTPConnection
-
- from infrahub.auth import AccountSession
- from infrahub.core.branch import Branch
- from infrahub.database import InfrahubDatabase
- from infrahub.services import InfrahubServices
-
-
-@dataclass
-class GraphqlParams:
- schema: GraphQLSchema
- context: GraphqlContext
-
-
-@dataclass
-class GraphqlContext:
- db: InfrahubDatabase
- branch: Branch
- types: dict
- at: Optional[Timestamp] = None
- related_node_ids: Optional[set] = None
- service: Optional[InfrahubServices] = None
- account_session: Optional[AccountSession] = None
- background: Optional[BackgroundTasks] = None
- request: Optional[HTTPConnection] = None
-
-
-def prepare_graphql_params(
- db: InfrahubDatabase,
- branch: Union[Branch, str],
- at: Optional[Union[Timestamp, str]] = None,
- account_session: Optional[AccountSession] = None,
- request: Optional[HTTPConnection] = None,
- service: Optional[InfrahubServices] = None,
- include_query: bool = True,
- include_mutation: bool = True,
- include_subscription: bool = True,
- include_types: bool = True,
-) -> GraphqlParams:
- branch = registry.get_branch_from_registry(branch=branch)
- schema = registry.schema.get_schema_branch(name=branch.name)
-
- gqlm = schema.get_graphql_manager()
- gql_schema = schema.get_graphql_schema(
- include_query=include_query,
- include_mutation=include_mutation,
- include_subscription=include_subscription,
- include_types=include_types,
- )
-
- if request and not service:
- service = request.app.state.service
-
- return GraphqlParams(
- schema=gql_schema,
- context=GraphqlContext(
- db=db,
- branch=branch,
- at=Timestamp(at),
- types=gqlm._graphql_types,
- related_node_ids=set(),
- background=BackgroundTasks(),
- request=request,
- service=service,
- account_session=account_session,
- ),
- )
-
-
-def generate_graphql_schema(
- db: InfrahubDatabase, # pylint: disable=unused-argument
- branch: Union[Branch, str],
- include_query: bool = True,
- include_mutation: bool = True,
- include_subscription: bool = True,
- include_types: bool = True,
-) -> GraphQLSchema:
- branch = registry.get_branch_from_registry(branch)
- schema = registry.schema.get_schema_branch(name=branch.name)
- return GraphQLSchemaManager(schema=schema).generate(
- include_query=include_query,
- include_mutation=include_mutation,
- include_subscription=include_subscription,
- include_types=include_types,
- )
diff --git a/backend/infrahub/graphql/analyzer.py b/backend/infrahub/graphql/analyzer.py
index f686e5ab6f..6aee1987c2 100644
--- a/backend/infrahub/graphql/analyzer.py
+++ b/backend/infrahub/graphql/analyzer.py
@@ -1,9 +1,6 @@
from typing import Any, Optional
-from graphql import (
- GraphQLSchema,
- OperationType,
-)
+from graphql import GraphQLSchema, OperationType
from infrahub_sdk.analyzer import GraphQLQueryAnalyzer
from infrahub_sdk.utils import extract_fields
@@ -12,8 +9,17 @@
class InfrahubGraphQLQueryAnalyzer(GraphQLQueryAnalyzer):
- def __init__(self, query: str, schema: Optional[GraphQLSchema] = None, branch: Optional[Branch] = None):
+ def __init__(
+ self,
+ query: str,
+ query_variables: Optional[dict[str, Any]] = None,
+ schema: Optional[GraphQLSchema] = None,
+ operation_name: Optional[str] = None,
+ branch: Optional[Branch] = None,
+ ) -> None:
self.branch: Optional[Branch] = branch
+ self.operation_name: Optional[str] = operation_name
+ self.query_variables: dict[str, Any] = query_variables or {}
super().__init__(query=query, schema=schema)
async def get_models_in_use(self, types: dict[str, Any]) -> set[str]:
diff --git a/backend/infrahub/graphql/api/dependencies.py b/backend/infrahub/graphql/api/dependencies.py
index 71aa7574f5..7bd391d131 100644
--- a/backend/infrahub/graphql/api/dependencies.py
+++ b/backend/infrahub/graphql/api/dependencies.py
@@ -5,9 +5,17 @@
from ..app import InfrahubGraphQLApp
from ..auth.query_permission_checker.anonymous_checker import AnonymousGraphQLPermissionChecker
from ..auth.query_permission_checker.checker import GraphQLQueryPermissionChecker
+from ..auth.query_permission_checker.default_branch_checker import DefaultBranchPermissionChecker
from ..auth.query_permission_checker.default_checker import DefaultGraphQLPermissionChecker
+from ..auth.query_permission_checker.merge_operation_checker import MergeBranchPermissionChecker
+from ..auth.query_permission_checker.object_permission_checker import (
+ AccountManagerPermissionChecker,
+ ObjectPermissionChecker,
+ PermissionManagerPermissionChecker,
+)
from ..auth.query_permission_checker.read_only_checker import ReadOnlyGraphQLPermissionChecker
from ..auth.query_permission_checker.read_write_checker import ReadWriteGraphQLPermissionChecker
+from ..auth.query_permission_checker.super_admin_checker import SuperAdminPermissionChecker
def get_anonymous_access_setting() -> bool:
@@ -17,8 +25,15 @@ def get_anonymous_access_setting() -> bool:
def build_graphql_query_permission_checker() -> GraphQLQueryPermissionChecker:
return GraphQLQueryPermissionChecker(
[
- ReadWriteGraphQLPermissionChecker(),
- ReadOnlyGraphQLPermissionChecker(),
+ # This checker never raises, it either terminates the checker chains (user is super admin) or go to the next one
+ SuperAdminPermissionChecker(),
+ DefaultBranchPermissionChecker(),
+ MergeBranchPermissionChecker(),
+ AccountManagerPermissionChecker(),
+ PermissionManagerPermissionChecker(),
+ ObjectPermissionChecker(),
+ ReadWriteGraphQLPermissionChecker(), # Deprecated, will be replace by either a global permission or object permissions
+ ReadOnlyGraphQLPermissionChecker(), # Deprecated, will be replace by either a global permission or object permissions
AnonymousGraphQLPermissionChecker(get_anonymous_access_setting),
DefaultGraphQLPermissionChecker(),
]
diff --git a/backend/infrahub/graphql/app.py b/backend/infrahub/graphql/app.py
index d838df0b8f..382d28d034 100644
--- a/backend/infrahub/graphql/app.py
+++ b/backend/infrahub/graphql/app.py
@@ -38,7 +38,7 @@
)
from opentelemetry import trace
from starlette.datastructures import UploadFile
-from starlette.requests import HTTPConnection, Request
+from starlette.requests import ClientDisconnect, HTTPConnection, Request
from starlette.responses import JSONResponse, Response
from starlette.websockets import WebSocket, WebSocketDisconnect, WebSocketState
@@ -47,8 +47,8 @@
from infrahub.core.registry import registry
from infrahub.core.timestamp import Timestamp
from infrahub.exceptions import BranchNotFoundError, Error
-from infrahub.graphql import prepare_graphql_params
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams, prepare_graphql_params
from infrahub.log import get_logger
from .metrics import (
@@ -104,7 +104,7 @@ def __init__(
middleware: Optional[Middleware] = None,
error_formatter: Callable[[GraphQLError], GraphQLFormattedError] = format_error,
execution_context_class: Optional[type[ExecutionContext]] = None,
- ):
+ ) -> None:
self._schema = schema
self.on_get = on_get
self.root_value = root_value
@@ -191,22 +191,37 @@ async def _handle_http_request(
operations = await _get_operation_from_request(request)
except ValueError as exc:
return JSONResponse({"errors": [exc.args[0]]}, status_code=400)
+ except ClientDisconnect as exc:
+ self.logger.error("Exception ClientDisconnect in _handle_http_request")
+ return JSONResponse({"errors": [str(exc)]}, status_code=400)
if isinstance(operations, list):
return JSONResponse({"errors": ["This server does not support batching"]}, status_code=400)
operation = operations
query = operation["query"]
+ variable_values = operation.get("variables")
+ operation_name = operation.get("operationName")
at = request.query_params.get("at", None)
graphql_params = prepare_graphql_params(
db=db, branch=branch, at=at, account_session=account_session, request=request
)
- analyzed_query = InfrahubGraphQLQueryAnalyzer(query=query, schema=graphql_params.schema, branch=branch)
- await self.permission_checker.check(account_session=account_session, analyzed_query=analyzed_query)
-
- variable_values = operation.get("variables")
- operation_name = operation.get("operationName")
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=query,
+ query_variables=variable_values,
+ schema=graphql_params.schema,
+ operation_name=operation_name,
+ branch=branch,
+ )
+ await self._evaluate_permissions(
+ db=db,
+ request=request,
+ query=analyzed_query,
+ query_parameters=graphql_params,
+ account_session=account_session,
+ branch=branch,
+ )
# if the query contains some mutation, it's not currently supported to set AT manually
if analyzed_query.contains_mutation:
@@ -221,13 +236,7 @@ async def _handle_http_request(
"Processing IntrospectionQuery .. ", branch=branch.name, nbr_object_in_schema=nbr_object_in_schema
)
- labels = {
- "type": "mutation" if analyzed_query.contains_mutation else "query",
- "branch": branch.name,
- "operation": operation_name if operation_name is not None else "",
- "name": analyzed_query.operations[0].name,
- "query_id": "",
- }
+ labels = self._set_labels(request=request, branch=branch, query=analyzed_query)
with trace.get_tracer(__name__).start_as_current_span("execute_graphql") as span:
span.set_attributes(labels)
@@ -272,23 +281,43 @@ async def _handle_http_request(
return json_response
+ def _set_labels(self, request: Request, branch: Branch, query: InfrahubGraphQLQueryAnalyzer) -> dict[str, Any]:
+ return {
+ "type": "mutation" if query.contains_mutation else "query",
+ "branch": branch.name,
+ "operation": query.operation_name if query.operation_name is not None else "",
+ "name": query.operations[0].name,
+ "query_id": "",
+ }
+
+ async def _evaluate_permissions(
+ self,
+ request: Request,
+ db: InfrahubDatabase,
+ query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ account_session: AccountSession,
+ branch: Branch,
+ ) -> None:
+ await self.permission_checker.check(
+ db=db,
+ account_session=account_session,
+ analyzed_query=query,
+ query_parameters=query_parameters,
+ branch=branch,
+ )
+
def _log_error(self, error: Exception) -> None:
if isinstance(error, Error):
if 500 <= error.HTTP_CODE <= 500:
- self.logger.error(
- "An exception occurred in resolvers",
- exc_info=error,
- )
+ self.logger.error("An exception occurred in resolvers", exc_info=error)
elif error.HTTP_CODE == 401:
self.logger.info("Permission denied within resolver", message=error.message)
else:
self.logger.debug("An exception occurred in resolvers", exc_info=error)
else:
- self.logger.critical(
- "Unhandled exception occurred in resolvers",
- exc_info=error,
- )
+ self.logger.critical("Unhandled exception occurred in resolvers", exc_info=error)
async def _run_websocket_server(self, db: InfrahubDatabase, branch: Branch, websocket: WebSocket) -> None:
subscriptions: dict[str, AsyncGenerator[Any, None]] = {}
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/anonymous_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/anonymous_checker.py
index 8b721b1704..254a5d3a90 100644
--- a/backend/infrahub/graphql/auth/query_permission_checker/anonymous_checker.py
+++ b/backend/infrahub/graphql/auth/query_permission_checker/anonymous_checker.py
@@ -1,20 +1,30 @@
from typing import Callable
from infrahub.auth import AccountSession
+from infrahub.core.branch import Branch
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import AuthorizationError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
-from .interface import GraphQLQueryPermissionCheckerInterface
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
class AnonymousGraphQLPermissionChecker(GraphQLQueryPermissionCheckerInterface):
- def __init__(self, anonymous_access_allowed_func: Callable[[], bool]):
+ def __init__(self, anonymous_access_allowed_func: Callable[[], bool]) -> None:
self.anonymous_access_allowed_func = anonymous_access_allowed_func
- async def supports(self, account_session: AccountSession) -> bool:
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
return not account_session.authenticated
- async def check(self, analyzed_query: InfrahubGraphQLQueryAnalyzer) -> None:
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
if self.anonymous_access_allowed_func() and not analyzed_query.contains_mutation:
- return
+ return CheckerResolution.TERMINATE
raise AuthorizationError("Authentication is required to perform this operation")
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/checker.py b/backend/infrahub/graphql/auth/query_permission_checker/checker.py
index e9625a8dc0..15a26ba39d 100644
--- a/backend/infrahub/graphql/auth/query_permission_checker/checker.py
+++ b/backend/infrahub/graphql/auth/query_permission_checker/checker.py
@@ -1,19 +1,34 @@
-from typing import List
-
from infrahub.auth import AccountSession
+from infrahub.core.branch import Branch
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import PermissionDeniedError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
-from .interface import GraphQLQueryPermissionCheckerInterface
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
class GraphQLQueryPermissionChecker:
- def __init__(self, sub_checkers: List[GraphQLQueryPermissionCheckerInterface]):
+ def __init__(self, sub_checkers: list[GraphQLQueryPermissionCheckerInterface]) -> None:
self.sub_checkers = sub_checkers
- async def check(self, account_session: AccountSession, analyzed_query: InfrahubGraphQLQueryAnalyzer) -> None:
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> None:
for sub_checker in self.sub_checkers:
- if await sub_checker.supports(account_session):
- await sub_checker.check(analyzed_query)
- return
+ if await sub_checker.supports(db=db, account_session=account_session, branch=branch):
+ resolution = await sub_checker.check(
+ db=db,
+ account_session=account_session,
+ analyzed_query=analyzed_query,
+ query_parameters=query_parameters,
+ branch=branch,
+ )
+ if resolution == CheckerResolution.TERMINATE:
+ return
raise PermissionDeniedError("The current account is not authorized to perform this operation")
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/default_branch_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/default_branch_checker.py
new file mode 100644
index 0000000000..ae04806ea4
--- /dev/null
+++ b/backend/infrahub/graphql/auth/query_permission_checker/default_branch_checker.py
@@ -0,0 +1,57 @@
+from infrahub.auth import AccountSession
+from infrahub.core import registry
+from infrahub.core.branch import Branch
+from infrahub.core.constants import GLOBAL_BRANCH_NAME, GlobalPermissions, PermissionDecision
+from infrahub.database import InfrahubDatabase
+from infrahub.exceptions import PermissionDeniedError
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
+
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
+
+
+class DefaultBranchPermissionChecker(GraphQLQueryPermissionCheckerInterface):
+ """Checker that makes sure a user account can edit data in the default branch."""
+
+ permission_required = f"global:{GlobalPermissions.EDIT_DEFAULT_BRANCH.value}:{PermissionDecision.ALLOW.value}"
+ exempt_operations = ["BranchCreate"]
+
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
+ return account_session.authenticated
+
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ can_edit_default_branch = False
+ for permission_backend in registry.permission_backends:
+ can_edit_default_branch = await permission_backend.has_permission(
+ db=db, account_id=account_session.account_id, permission=self.permission_required, branch=branch
+ )
+ if can_edit_default_branch:
+ break
+
+ operates_on_default_branch = analyzed_query.branch is None or analyzed_query.branch.name in (
+ GLOBAL_BRANCH_NAME,
+ registry.default_branch,
+ )
+ is_exempt_operation = analyzed_query.operation_name is not None and (
+ analyzed_query.operation_name in self.exempt_operations
+ or analyzed_query.operation_name.startswith("InfrahubAccount") # Allow user to manage self
+ )
+
+ if (
+ not can_edit_default_branch
+ and operates_on_default_branch
+ and analyzed_query.contains_mutation
+ and not is_exempt_operation
+ ):
+ raise PermissionDeniedError(
+ f"You are not allowed to change data in the default branch '{registry.default_branch}'"
+ )
+
+ return CheckerResolution.NEXT_CHECKER
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/default_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/default_checker.py
index c4c1754fe5..3d156f9723 100644
--- a/backend/infrahub/graphql/auth/query_permission_checker/default_checker.py
+++ b/backend/infrahub/graphql/auth/query_permission_checker/default_checker.py
@@ -1,13 +1,23 @@
from infrahub.auth import AccountSession
+from infrahub.core.branch import Branch
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import AuthorizationError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
-from .interface import GraphQLQueryPermissionCheckerInterface
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
class DefaultGraphQLPermissionChecker(GraphQLQueryPermissionCheckerInterface):
- async def supports(self, account_session: AccountSession) -> bool:
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
return True
- async def check(self, analyzed_query: InfrahubGraphQLQueryAnalyzer) -> None:
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
raise AuthorizationError("Authentication is required to perform this operation")
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/interface.py b/backend/infrahub/graphql/auth/query_permission_checker/interface.py
index a5c62d8b41..ff0a00e2ea 100644
--- a/backend/infrahub/graphql/auth/query_permission_checker/interface.py
+++ b/backend/infrahub/graphql/auth/query_permission_checker/interface.py
@@ -1,12 +1,28 @@
from abc import ABC, abstractmethod
+from enum import Enum
from infrahub.auth import AccountSession
+from infrahub.core.branch import Branch
+from infrahub.database import InfrahubDatabase
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
+
+
+class CheckerResolution(Enum):
+ TERMINATE = 0
+ NEXT_CHECKER = 1
class GraphQLQueryPermissionCheckerInterface(ABC):
@abstractmethod
- async def supports(self, account_session: AccountSession) -> bool: ...
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: ...
@abstractmethod
- async def check(self, analyzed_query: InfrahubGraphQLQueryAnalyzer) -> None: ...
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution: ...
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py
new file mode 100644
index 0000000000..dbadc65112
--- /dev/null
+++ b/backend/infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py
@@ -0,0 +1,43 @@
+from infrahub.auth import AccountSession
+from infrahub.core import registry
+from infrahub.core.branch import Branch
+from infrahub.core.constants import GlobalPermissions
+from infrahub.database import InfrahubDatabase
+from infrahub.exceptions import PermissionDeniedError
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
+
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
+
+
+class MergeBranchPermissionChecker(GraphQLQueryPermissionCheckerInterface):
+ """Checker that makes sure a user account can merge a branch without going through a proposed change."""
+
+ permission_required = f"global:{GlobalPermissions.MERGE_BRANCH.value}:allow"
+
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
+ return account_session.authenticated
+
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ if "BranchMerge" in [operation.name for operation in analyzed_query.operations]:
+ can_merge_branch = False
+ for permission_backend in registry.permission_backends:
+ can_merge_branch = await permission_backend.has_permission(
+ db=db, account_id=account_session.account_id, permission=self.permission_required, branch=branch
+ )
+ if can_merge_branch:
+ break
+
+ if not can_merge_branch:
+ raise PermissionDeniedError("You are not allowed to merge a branch")
+
+ return CheckerResolution.TERMINATE
+
+ return CheckerResolution.NEXT_CHECKER
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/object_permission_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/object_permission_checker.py
new file mode 100644
index 0000000000..2f31be77b4
--- /dev/null
+++ b/backend/infrahub/graphql/auth/query_permission_checker/object_permission_checker.py
@@ -0,0 +1,212 @@
+from infrahub.auth import AccountSession
+from infrahub.core import registry
+from infrahub.core.account import ObjectPermission
+from infrahub.core.branch import Branch
+from infrahub.core.constants import GlobalPermissions, InfrahubKind, PermissionDecision
+from infrahub.core.manager import get_schema
+from infrahub.core.schema.node_schema import NodeSchema
+from infrahub.database import InfrahubDatabase
+from infrahub.exceptions import PermissionDeniedError
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
+from infrahub.utils import extract_camelcase_words
+
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
+
+
+class ObjectPermissionChecker(GraphQLQueryPermissionCheckerInterface):
+ """Checker that makes sure a user account can perform some action on some kind of objects."""
+
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
+ return account_session.authenticated
+
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ kinds = await analyzed_query.get_models_in_use(types=query_parameters.context.types)
+
+ # Identify which operations are performed. As we don't have a mapping between kinds and the
+ # operation we currently require permissions all defined permissions for all objects
+ # within the GraphQL query / mutation
+ actions: set[str] = set()
+ for operation in analyzed_query.operations:
+ for kind in kinds:
+ if operation.name and operation.name.startswith(kind):
+ # An empty string after prefix removal means a query to "view"
+ query_action = operation.name[len(kind) :].lower() or "view"
+ if query_action == "upsert":
+ # Require both create and update for Upsert mutations
+ actions.add("create")
+ actions.add("update")
+ else:
+ actions.add(query_action)
+
+ # Infer required permissions from the kind/operation map
+ permissions: list[str] = []
+ for action in actions:
+ for kind in kinds:
+ extracted_words = extract_camelcase_words(kind)
+ permissions.append(
+ str(
+ # Create a object permission instance just to get its string representation
+ ObjectPermission(
+ id="",
+ branch=branch.name,
+ namespace=extracted_words[0],
+ name="".join(extracted_words[1:]),
+ action=action.lower(),
+ decision=PermissionDecision.ALLOW.value,
+ )
+ )
+ )
+
+ for permission in permissions:
+ has_permission = False
+ for permission_backend in registry.permission_backends:
+ has_permission = await permission_backend.has_permission(
+ db=db, account_id=account_session.account_id, permission=permission, branch=branch
+ )
+ if not has_permission:
+ raise PermissionDeniedError(f"You do not have the following permission: {permission}")
+
+ return CheckerResolution.NEXT_CHECKER
+
+
+class AccountManagerPermissionChecker(GraphQLQueryPermissionCheckerInterface):
+ """Checker that makes sure a user account can perform actions on account related objects.
+
+ This is similar to object permission checker except that we care for any operations on any account related kinds.
+ """
+
+ permission_required = f"global:{GlobalPermissions.MANAGE_ACCOUNTS.value}:{PermissionDecision.ALLOW.value}"
+
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
+ return account_session.authenticated
+
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ is_account_operation = False
+ kinds = await analyzed_query.get_models_in_use(types=query_parameters.context.types)
+ operation_names = [operation.name for operation in analyzed_query.operations]
+
+ for kind in kinds:
+ schema = get_schema(db=db, branch=branch, node_schema=kind)
+ if is_account_operation := kind in (
+ InfrahubKind.GENERICACCOUNT,
+ InfrahubKind.ACCOUNTGROUP,
+ InfrahubKind.ACCOUNTROLE,
+ ) or (isinstance(schema, NodeSchema) and InfrahubKind.GENERICACCOUNT in schema.inherit_from):
+ break
+
+ # Ignore non-account related operation or viewing account own profile
+ if not is_account_operation or operation_names == ["AccountProfile"]:
+ return CheckerResolution.NEXT_CHECKER
+
+ has_permission = False
+ for permission_backend in registry.permission_backends:
+ if has_permission := await permission_backend.has_permission(
+ db=db, account_id=account_session.account_id, permission=self.permission_required, branch=branch
+ ):
+ break
+
+ if not has_permission and analyzed_query.contains_mutation:
+ raise PermissionDeniedError("You do not have the permission to manage user accounts, groups or roles")
+
+ return CheckerResolution.NEXT_CHECKER
+
+
+class PermissionManagerPermissionChecker(GraphQLQueryPermissionCheckerInterface):
+ """Checker that makes sure a user account can perform actions on permission related object.
+
+ This is similar to object permission checker except that we care for any operations on any permission related kinds.
+ """
+
+ permission_required = f"global:{GlobalPermissions.MANAGE_PERMISSIONS.value}:{PermissionDecision.ALLOW.value}"
+
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
+ return account_session.authenticated
+
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ is_permission_operation = False
+ kinds = await analyzed_query.get_models_in_use(types=query_parameters.context.types)
+
+ for kind in kinds:
+ schema = get_schema(db=db, branch=branch, node_schema=kind)
+ if is_permission_operation := kind in (
+ InfrahubKind.BASEPERMISSION,
+ InfrahubKind.GLOBALPERMISSION,
+ InfrahubKind.OBJECTPERMISSION,
+ ) or (isinstance(schema, NodeSchema) and InfrahubKind.BASEPERMISSION in schema.inherit_from):
+ break
+
+ if not is_permission_operation:
+ return CheckerResolution.NEXT_CHECKER
+
+ for permission_backend in registry.permission_backends:
+ if not await permission_backend.has_permission(
+ db=db, account_id=account_session.account_id, permission=self.permission_required, branch=branch
+ ):
+ raise PermissionDeniedError("You do not have the permission to manage permissions")
+
+ return CheckerResolution.NEXT_CHECKER
+
+
+class RepositoryManagerPermissionChecker(GraphQLQueryPermissionCheckerInterface):
+ """Checker that makes sure a user account can add/edit/delete repository objects.
+
+ This is similar to object permission checker except that we only care about mutations on repositories.
+ """
+
+ permission_required = f"global:{GlobalPermissions.MANAGE_REPOSITORIES.value}:{PermissionDecision.ALLOW.value}"
+
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
+ return account_session.authenticated
+
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ is_repository_operation = False
+ kinds = await analyzed_query.get_models_in_use(types=query_parameters.context.types)
+
+ for kind in kinds:
+ schema = get_schema(db=db, branch=branch, node_schema=kind)
+ if is_repository_operation := kind in (
+ InfrahubKind.GENERICREPOSITORY,
+ InfrahubKind.REPOSITORY,
+ InfrahubKind.READONLYREPOSITORY,
+ ) or (isinstance(schema, NodeSchema) and InfrahubKind.GENERICREPOSITORY in schema.inherit_from):
+ break
+
+ if not is_repository_operation or not analyzed_query.contains_mutation:
+ return CheckerResolution.NEXT_CHECKER
+
+ for permission_backend in registry.permission_backends:
+ if not await permission_backend.has_permission(
+ db=db, account_id=account_session.account_id, permission=self.permission_required, branch=branch
+ ):
+ raise PermissionDeniedError("You do not have the permission to manage repositories")
+
+ return CheckerResolution.NEXT_CHECKER
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/read_only_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/read_only_checker.py
index 26c606921e..da16978cf1 100644
--- a/backend/infrahub/graphql/auth/query_permission_checker/read_only_checker.py
+++ b/backend/infrahub/graphql/auth/query_permission_checker/read_only_checker.py
@@ -1,22 +1,34 @@
from graphql import OperationType
from infrahub.auth import AccountSession
+from infrahub.core.branch import Branch
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import PermissionDeniedError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
-from .interface import GraphQLQueryPermissionCheckerInterface
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
class ReadOnlyGraphQLPermissionChecker(GraphQLQueryPermissionCheckerInterface):
allowed_readonly_mutations = ["InfrahubAccountSelfUpdate"]
- async def supports(self, account_session: AccountSession) -> bool:
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
return account_session.authenticated and account_session.read_only
- async def check(self, analyzed_query: InfrahubGraphQLQueryAnalyzer) -> None:
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
for operation in analyzed_query.operations:
if (
operation.operation_type == OperationType.MUTATION
and operation.name not in self.allowed_readonly_mutations
):
raise PermissionDeniedError("The current account is not authorized to perform this operation")
+
+ return CheckerResolution.TERMINATE
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/read_write_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/read_write_checker.py
index 1c3d72e27d..e236532ea3 100644
--- a/backend/infrahub/graphql/auth/query_permission_checker/read_write_checker.py
+++ b/backend/infrahub/graphql/auth/query_permission_checker/read_write_checker.py
@@ -1,12 +1,22 @@
from infrahub.auth import AccountSession
+from infrahub.core.branch import Branch
+from infrahub.database import InfrahubDatabase
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
-from .interface import GraphQLQueryPermissionCheckerInterface
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
class ReadWriteGraphQLPermissionChecker(GraphQLQueryPermissionCheckerInterface):
- async def supports(self, account_session: AccountSession) -> bool:
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
return account_session.authenticated and not account_session.read_only
- async def check(self, analyzed_query: InfrahubGraphQLQueryAnalyzer) -> None:
- return
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ return CheckerResolution.TERMINATE
diff --git a/backend/infrahub/graphql/auth/query_permission_checker/super_admin_checker.py b/backend/infrahub/graphql/auth/query_permission_checker/super_admin_checker.py
new file mode 100644
index 0000000000..a0e5982b26
--- /dev/null
+++ b/backend/infrahub/graphql/auth/query_permission_checker/super_admin_checker.py
@@ -0,0 +1,34 @@
+from infrahub.auth import AccountSession
+from infrahub.core import registry
+from infrahub.core.branch import Branch
+from infrahub.core.constants import GlobalPermissions
+from infrahub.database import InfrahubDatabase
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import GraphqlParams
+
+from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
+
+
+class SuperAdminPermissionChecker(GraphQLQueryPermissionCheckerInterface):
+ """Checker allows a user to do anything (if the checker runs first)."""
+
+ permission_required = f"global:{GlobalPermissions.SUPER_ADMIN.value}:allow"
+
+ async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
+ return account_session.authenticated
+
+ async def check(
+ self,
+ db: InfrahubDatabase,
+ account_session: AccountSession,
+ analyzed_query: InfrahubGraphQLQueryAnalyzer,
+ query_parameters: GraphqlParams,
+ branch: Branch,
+ ) -> CheckerResolution:
+ for permission_backend in registry.permission_backends:
+ if await permission_backend.has_permission(
+ db=db, account_id=account_session.account_id, permission=self.permission_required, branch=branch
+ ):
+ return CheckerResolution.TERMINATE
+
+ return CheckerResolution.NEXT_CHECKER
diff --git a/backend/infrahub/graphql/initialization.py b/backend/infrahub/graphql/initialization.py
new file mode 100644
index 0000000000..757957e478
--- /dev/null
+++ b/backend/infrahub/graphql/initialization.py
@@ -0,0 +1,110 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Optional, Union
+
+from starlette.background import BackgroundTasks
+
+from infrahub.core import registry
+from infrahub.core.timestamp import Timestamp
+from infrahub.exceptions import InitializationError
+
+from .manager import GraphQLSchemaManager
+
+if TYPE_CHECKING:
+ from graphql import GraphQLSchema
+ from starlette.requests import HTTPConnection
+
+ from infrahub.auth import AccountSession
+ from infrahub.core.branch import Branch
+ from infrahub.database import InfrahubDatabase
+ from infrahub.services import InfrahubServices
+
+
+@dataclass
+class GraphqlParams:
+ schema: GraphQLSchema
+ context: GraphqlContext
+
+
+@dataclass
+class GraphqlContext:
+ db: InfrahubDatabase
+ branch: Branch
+ types: dict
+ at: Optional[Timestamp] = None
+ related_node_ids: Optional[set] = None
+ service: Optional[InfrahubServices] = None
+ account_session: Optional[AccountSession] = None
+ background: Optional[BackgroundTasks] = None
+ request: Optional[HTTPConnection] = None
+
+ @property
+ def active_account_session(self) -> AccountSession:
+ """Return an account session or raise an error
+
+ Eventualy this property should be removed, that can be done after self.account_session is no longer optional
+ """
+ if self.account_session:
+ return self.account_session
+ raise InitializationError("GraphQLContext doesn't contain an account_session")
+
+
+def prepare_graphql_params(
+ db: InfrahubDatabase,
+ branch: Union[Branch, str],
+ at: Optional[Union[Timestamp, str]] = None,
+ account_session: Optional[AccountSession] = None,
+ request: Optional[HTTPConnection] = None,
+ service: Optional[InfrahubServices] = None,
+ include_query: bool = True,
+ include_mutation: bool = True,
+ include_subscription: bool = True,
+ include_types: bool = True,
+) -> GraphqlParams:
+ branch = registry.get_branch_from_registry(branch=branch)
+ schema = registry.schema.get_schema_branch(name=branch.name)
+
+ gqlm = schema.get_graphql_manager()
+ gql_schema = schema.get_graphql_schema(
+ include_query=include_query,
+ include_mutation=include_mutation,
+ include_subscription=include_subscription,
+ include_types=include_types,
+ )
+
+ if request and not service:
+ service = request.app.state.service
+
+ return GraphqlParams(
+ schema=gql_schema,
+ context=GraphqlContext(
+ db=db,
+ branch=branch,
+ at=Timestamp(at),
+ types=gqlm._graphql_types,
+ related_node_ids=set(),
+ background=BackgroundTasks(),
+ request=request,
+ service=service,
+ account_session=account_session,
+ ),
+ )
+
+
+def generate_graphql_schema(
+ db: InfrahubDatabase, # pylint: disable=unused-argument
+ branch: Union[Branch, str],
+ include_query: bool = True,
+ include_mutation: bool = True,
+ include_subscription: bool = True,
+ include_types: bool = True,
+) -> GraphQLSchema:
+ branch = registry.get_branch_from_registry(branch)
+ schema = registry.schema.get_schema_branch(name=branch.name)
+ return GraphQLSchemaManager(schema=schema).generate(
+ include_query=include_query,
+ include_mutation=include_mutation,
+ include_subscription=include_subscription,
+ include_types=include_types,
+ )
diff --git a/backend/infrahub/graphql/manager.py b/backend/infrahub/graphql/manager.py
index 246105db18..805575aa1c 100644
--- a/backend/infrahub/graphql/manager.py
+++ b/backend/infrahub/graphql/manager.py
@@ -23,15 +23,18 @@
from .directives import DIRECTIVES
from .enums import generate_graphql_enum, get_enum_attribute_type_name
from .metrics import SCHEMA_GENERATE_GRAPHQL_METRICS
-from .mutations import (
- InfrahubArtifactDefinitionMutation,
+from .mutations.artifact_definition import InfrahubArtifactDefinitionMutation
+from .mutations.ipam import (
InfrahubIPAddressMutation,
InfrahubIPNamespaceMutation,
InfrahubIPPrefixMutation,
- InfrahubMutation,
+)
+from .mutations.main import InfrahubMutation
+from .mutations.menu import InfrahubCoreMenuMutation
+from .mutations.proposed_change import InfrahubProposedChangeMutation
+from .mutations.repository import InfrahubRepositoryMutation
+from .mutations.resource_manager import (
InfrahubNumberPoolMutation,
- InfrahubProposedChangeMutation,
- InfrahubRepositoryMutation,
)
from .queries.diff.diff import (
DiffSummaryElementAttribute,
@@ -39,17 +42,20 @@
DiffSummaryElementRelationshipOne,
)
from .resolver import (
+ account_resolver,
ancestors_resolver,
+ default_paginated_list_resolver,
default_resolver,
descendants_resolver,
many_relationship_resolver,
single_relationship_resolver,
)
-from .schema import InfrahubBaseMutation, InfrahubBaseQuery, account_resolver, default_paginated_list_resolver
+from .schema import InfrahubBaseMutation, InfrahubBaseQuery
from .subscription import InfrahubBaseSubscription
from .types import (
InfrahubInterface,
InfrahubObject,
+ PaginatedObjectPermission,
RelatedIPAddressNodeInput,
RelatedNodeInput,
RelatedPrefixNodeInput,
@@ -60,7 +66,7 @@
if TYPE_CHECKING:
from graphql import GraphQLSchema
- from infrahub.core.schema_manager import SchemaBranch
+ from infrahub.core.schema.schema_branch import SchemaBranch
class DeleteInput(graphene.InputObjectType):
@@ -94,7 +100,7 @@ class GraphQLSchemaManager: # pylint: disable=too-many-public-methods
"DiffSummaryElementRelationshipMany": DiffSummaryElementRelationshipMany,
}
- def __init__(self, schema: SchemaBranch):
+ def __init__(self, schema: SchemaBranch) -> None:
self.schema = schema
self._graphql_types: dict[str, GraphQLTypes] = {}
@@ -410,6 +416,7 @@ def generate_mutation_mixin(self) -> type[object]:
InfrahubKind.GRAPHQLQUERY: InfrahubGraphQLQueryMutation,
InfrahubKind.NAMESPACE: InfrahubIPNamespaceMutation,
InfrahubKind.NUMBERPOOL: InfrahubNumberPoolMutation,
+ InfrahubKind.MENUITEM: InfrahubCoreMenuMutation,
}
if isinstance(node_schema, NodeSchema) and node_schema.is_ip_prefix():
@@ -878,6 +885,9 @@ def generate_graphql_paginated_object(
"Meta": type("Meta", (object,), meta_attrs),
}
+ if isinstance(schema, (NodeSchema, GenericSchema)):
+ main_attrs["permissions"] = graphene.Field(PaginatedObjectPermission, required=True)
+
graphql_paginated_object = type(object_name, (InfrahubObject,), main_attrs)
if populate_cache:
diff --git a/backend/infrahub/graphql/mutations/__init__.py b/backend/infrahub/graphql/mutations/__init__.py
index 4ab2dcc100..e69de29bb2 100644
--- a/backend/infrahub/graphql/mutations/__init__.py
+++ b/backend/infrahub/graphql/mutations/__init__.py
@@ -1,98 +0,0 @@
-from .account import InfrahubAccountSelfUpdate, InfrahubAccountTokenCreate, InfrahubAccountTokenDelete
-from .artifact_definition import InfrahubArtifactDefinitionMutation
-from .attribute import (
- AnyAttributeCreate,
- AnyAttributeUpdate,
- BoolAttributeCreate,
- BoolAttributeUpdate,
- CheckboxAttributeCreate,
- CheckboxAttributeUpdate,
- JSONAttributeCreate,
- JSONAttributeUpdate,
- ListAttributeCreate,
- ListAttributeUpdate,
- NumberAttributeCreate,
- NumberAttributeUpdate,
- StringAttributeCreate,
- StringAttributeUpdate,
- TextAttributeCreate,
- TextAttributeUpdate,
-)
-from .branch import (
- BranchCreate,
- BranchCreateInput,
- BranchDelete,
- BranchMerge,
- BranchNameInput,
- BranchRebase,
- BranchUpdate,
- BranchValidate,
-)
-from .diff import DiffUpdateMutation
-from .diff_conflict import ResolveDiffConflict
-from .ipam import InfrahubIPAddressMutation, InfrahubIPNamespaceMutation, InfrahubIPPrefixMutation
-from .main import InfrahubMutation, InfrahubMutationMixin, InfrahubMutationOptions
-from .proposed_change import (
- InfrahubProposedChangeMutation,
- ProposedChangeRequestRunCheck,
-)
-from .relationship import RelationshipAdd, RelationshipRemove
-from .repository import InfrahubRepositoryMutation, ProcessRepository, ValidateRepositoryConnectivity
-from .resource_manager import InfrahubNumberPoolMutation, IPAddressPoolGetResource, IPPrefixPoolGetResource
-from .schema import SchemaDropdownAdd, SchemaDropdownRemove, SchemaEnumAdd, SchemaEnumRemove
-from .task import TaskCreate, TaskUpdate
-
-__all__ = [
- "AnyAttributeCreate",
- "AnyAttributeUpdate",
- "BoolAttributeCreate",
- "BoolAttributeUpdate",
- "BranchCreate",
- "BranchCreateInput",
- "BranchRebase",
- "BranchValidate",
- "BranchDelete",
- "BranchMerge",
- "BranchNameInput",
- "BranchUpdate",
- "CheckboxAttributeCreate",
- "CheckboxAttributeUpdate",
- "DiffUpdateMutation",
- "InfrahubAccountSelfUpdate",
- "InfrahubAccountTokenCreate",
- "InfrahubAccountTokenDelete",
- "IPPrefixPoolGetResource",
- "IPAddressPoolGetResource",
- "InfrahubArtifactDefinitionMutation",
- "InfrahubNumberPoolMutation",
- "InfrahubIPAddressMutation",
- "InfrahubIPNamespaceMutation",
- "InfrahubIPPrefixMutation",
- "InfrahubRepositoryMutation",
- "InfrahubMutationOptions",
- "InfrahubMutation",
- "InfrahubMutationMixin",
- "InfrahubProposedChangeMutation",
- "JSONAttributeCreate",
- "JSONAttributeUpdate",
- "ListAttributeCreate",
- "ListAttributeUpdate",
- "NumberAttributeCreate",
- "NumberAttributeUpdate",
- "ProposedChangeRequestRunCheck",
- "ProcessRepository",
- "RelationshipAdd",
- "RelationshipRemove",
- "ResolveDiffConflict",
- "StringAttributeCreate",
- "StringAttributeUpdate",
- "TextAttributeCreate",
- "TextAttributeUpdate",
- "SchemaDropdownAdd",
- "SchemaDropdownRemove",
- "SchemaEnumAdd",
- "SchemaEnumRemove",
- "TaskCreate",
- "TaskUpdate",
- "ValidateRepositoryConnectivity",
-]
diff --git a/backend/infrahub/graphql/mutations/account.py b/backend/infrahub/graphql/mutations/account.py
index c1d15c28d2..1ecb40b303 100644
--- a/backend/infrahub/graphql/mutations/account.py
+++ b/backend/infrahub/graphql/mutations/account.py
@@ -18,7 +18,7 @@
from ..types import InfrahubObjectType
if TYPE_CHECKING:
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
# pylint: disable=unused-argument
diff --git a/backend/infrahub/graphql/mutations/artifact_definition.py b/backend/infrahub/graphql/mutations/artifact_definition.py
index 7a9268fc96..caef54be9c 100644
--- a/backend/infrahub/graphql/mutations/artifact_definition.py
+++ b/backend/infrahub/graphql/mutations/artifact_definition.py
@@ -17,7 +17,7 @@
from infrahub.core.branch import Branch
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
log = get_logger()
@@ -44,7 +44,6 @@ def __init_subclass_with_meta__( # pylint: disable=arguments-differ
@classmethod
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -53,7 +52,7 @@ async def mutate_create(
) -> tuple[Node, Self]:
context: GraphqlContext = info.context
- artifact_definition, result = await super().mutate_create(root=root, info=info, data=data, branch=branch, at=at)
+ artifact_definition, result = await super().mutate_create(info=info, data=data, branch=branch, at=at)
events = [
messages.RequestArtifactDefinitionGenerate(artifact_definition=artifact_definition.id, branch=branch.name),
@@ -68,7 +67,6 @@ async def mutate_create(
@classmethod
async def mutate_update(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -78,7 +76,7 @@ async def mutate_update(
) -> tuple[Node, Self]:
context: GraphqlContext = info.context
- artifact_definition, result = await super().mutate_update(root=root, info=info, data=data, branch=branch, at=at)
+ artifact_definition, result = await super().mutate_update(info=info, data=data, branch=branch, at=at)
events = [
messages.RequestArtifactDefinitionGenerate(artifact_definition=artifact_definition.id, branch=branch.name),
diff --git a/backend/infrahub/graphql/mutations/attribute.py b/backend/infrahub/graphql/mutations/attribute.py
index 244ad10ab8..568b1edf6b 100644
--- a/backend/infrahub/graphql/mutations/attribute.py
+++ b/backend/infrahub/graphql/mutations/attribute.py
@@ -12,7 +12,7 @@ class BaseAttributeCreate(InputObjectType):
owner = String(required=False)
@classmethod
- def __init_subclass__(cls, **kwargs):
+ def __init_subclass__(cls, **kwargs) -> None:
super().__init_subclass__(**kwargs)
registry.input_type[cls.__name__] = cls
@@ -25,7 +25,7 @@ class BaseAttributeUpdate(InputObjectType):
owner = String(required=False)
@classmethod
- def __init_subclass__(cls, **kwargs):
+ def __init_subclass__(cls, **kwargs) -> None:
super().__init_subclass__(**kwargs)
registry.input_type[cls.__name__] = cls
diff --git a/backend/infrahub/graphql/mutations/branch.py b/backend/infrahub/graphql/mutations/branch.py
index 2c484ff625..a86c03e311 100644
--- a/backend/infrahub/graphql/mutations/branch.py
+++ b/backend/infrahub/graphql/mutations/branch.py
@@ -29,7 +29,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
# pylint: disable=unused-argument
diff --git a/backend/infrahub/graphql/mutations/diff.py b/backend/infrahub/graphql/mutations/diff.py
index 5c2e32f137..8941b999ff 100644
--- a/backend/infrahub/graphql/mutations/diff.py
+++ b/backend/infrahub/graphql/mutations/diff.py
@@ -9,7 +9,7 @@
from infrahub.message_bus import messages
if TYPE_CHECKING:
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
class DiffUpdateInput(InputObjectType):
diff --git a/backend/infrahub/graphql/mutations/diff_conflict.py b/backend/infrahub/graphql/mutations/diff_conflict.py
index 8877934f24..b5ae8aa11f 100644
--- a/backend/infrahub/graphql/mutations/diff_conflict.py
+++ b/backend/infrahub/graphql/mutations/diff_conflict.py
@@ -15,7 +15,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
# pylint: disable=unused-argument
diff --git a/backend/infrahub/graphql/mutations/graphql_query.py b/backend/infrahub/graphql/mutations/graphql_query.py
index e08a8862c5..fbe8c81f4f 100644
--- a/backend/infrahub/graphql/mutations/graphql_query.py
+++ b/backend/infrahub/graphql/mutations/graphql_query.py
@@ -14,7 +14,7 @@
from .main import InfrahubMutationOptions
if TYPE_CHECKING:
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class InfrahubGraphQLQueryMutation(InfrahubMutationMixin, Mutation):
@@ -60,7 +60,6 @@ async def extract_query_info(
@classmethod
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -71,14 +70,13 @@ async def mutate_create(
data.update(await cls.extract_query_info(info=info, data=data, branch=context.branch))
- obj, result = await super().mutate_create(root=root, info=info, data=data, branch=branch, at=at)
+ obj, result = await super().mutate_create(info=info, data=data, branch=branch, at=at)
return obj, result
@classmethod
async def mutate_update(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -90,6 +88,6 @@ async def mutate_update(
data.update(await cls.extract_query_info(info=info, data=data, branch=context.branch))
- obj, result = await super().mutate_update(root=root, info=info, data=data, branch=branch, at=at)
+ obj, result = await super().mutate_update(info=info, data=data, branch=branch, at=at)
return obj, result
diff --git a/backend/infrahub/graphql/mutations/ipam.py b/backend/infrahub/graphql/mutations/ipam.py
index d147b0412c..17e3b36139 100644
--- a/backend/infrahub/graphql/mutations/ipam.py
+++ b/backend/infrahub/graphql/mutations/ipam.py
@@ -20,7 +20,7 @@
from .main import InfrahubMutationMixin, InfrahubMutationOptions
if TYPE_CHECKING:
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
log = get_logger()
@@ -64,7 +64,6 @@ def __init_subclass_with_meta__( # pylint: disable=arguments-differ
@classmethod
async def mutate_delete(
cls,
- root,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -73,7 +72,7 @@ async def mutate_delete(
if data["id"] == registry.default_ipnamespace:
raise ValueError("Cannot delete default IPAM namespace")
- return await super().mutate_delete(root=root, info=info, data=data, branch=branch, at=at)
+ return await super().mutate_delete(info=info, data=data, branch=branch, at=at)
class InfrahubIPAddressMutation(InfrahubMutationMixin, Mutation):
@@ -98,7 +97,6 @@ def __init_subclass_with_meta__( # pylint: disable=arguments-differ
@retry_db_transaction(name="ipaddress_create")
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -125,7 +123,6 @@ async def mutate_create(
@retry_db_transaction(name="ipaddress_update")
async def mutate_update(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -165,7 +162,6 @@ async def mutate_update(
@classmethod
async def mutate_upsert(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -178,7 +174,7 @@ async def mutate_upsert(
await validate_namespace(db=db, data=data)
prefix, result, created = await super().mutate_upsert(
- root=root, info=info, data=data, branch=branch, at=at, node_getters=node_getters, database=db
+ info=info, data=data, branch=branch, at=at, node_getters=node_getters, database=db
)
return prefix, result, created
@@ -186,13 +182,12 @@ async def mutate_upsert(
@classmethod
async def mutate_delete(
cls,
- root,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
at: str,
):
- return await super().mutate_delete(root=root, info=info, data=data, branch=branch, at=at)
+ return await super().mutate_delete(info=info, data=data, branch=branch, at=at)
class InfrahubIPPrefixMutation(InfrahubMutationMixin, Mutation):
@@ -217,7 +212,6 @@ def __init_subclass_with_meta__( # pylint: disable=arguments-differ
@retry_db_transaction(name="ipprefix_create")
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -244,7 +238,6 @@ async def mutate_create(
@retry_db_transaction(name="ipprefix_update")
async def mutate_update(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -284,7 +277,6 @@ async def mutate_update(
@classmethod
async def mutate_upsert(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -297,7 +289,7 @@ async def mutate_upsert(
await validate_namespace(db=db, data=data)
prefix, result, created = await super().mutate_upsert(
- root=root, info=info, data=data, branch=branch, at=at, node_getters=node_getters, database=db
+ info=info, data=data, branch=branch, at=at, node_getters=node_getters, database=db
)
return prefix, result, created
@@ -306,7 +298,6 @@ async def mutate_upsert(
@retry_db_transaction(name="ipprefix_delete")
async def mutate_delete(
cls,
- root,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
diff --git a/backend/infrahub/graphql/mutations/main.py b/backend/infrahub/graphql/mutations/main.py
index 7e65113fc7..2f8a3de052 100644
--- a/backend/infrahub/graphql/mutations/main.py
+++ b/backend/infrahub/graphql/mutations/main.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Optional, Union
+from typing import TYPE_CHECKING, Any, Optional, Union
from graphene import InputObjectType, Mutation
from graphene.types.mutation import MutationOptions
@@ -23,10 +23,9 @@
from infrahub.core.timestamp import Timestamp
from infrahub.database import retry_db_transaction
from infrahub.dependencies.registry import get_component_registry
+from infrahub.events import EventMeta, NodeMutatedEvent
from infrahub.exceptions import ValidationError
from infrahub.log import get_log_data, get_logger
-from infrahub.message_bus import Meta, messages
-from infrahub.services import services
from infrahub.worker import WORKER_IDENTITY
from .node_getter.by_default_filter import MutationNodeGetterByDefaultFilter
@@ -39,7 +38,7 @@
from infrahub.core.branch import Branch
from infrahub.database import InfrahubDatabase
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
from .node_getter.interface import MutationNodeGetterInterface
# pylint: disable=unused-argument
@@ -56,7 +55,7 @@ class InfrahubMutationOptions(MutationOptions):
class InfrahubMutationMixin:
@classmethod
- async def mutate(cls, root: dict, info: GraphQLResolveInfo, *args, **kwargs):
+ async def mutate(cls, root: dict, info: GraphQLResolveInfo, *args: Any, **kwargs):
context: GraphqlContext = info.context
obj = None
@@ -65,14 +64,10 @@ async def mutate(cls, root: dict, info: GraphQLResolveInfo, *args, **kwargs):
validate_mutation_permissions(operation=cls.__name__, account_session=context.account_session)
if "Create" in cls.__name__:
- obj, mutation = await cls.mutate_create(
- root=root, info=info, branch=context.branch, at=context.at, **kwargs
- )
+ obj, mutation = await cls.mutate_create(info=info, branch=context.branch, at=context.at, **kwargs)
action = MutationAction.ADDED
elif "Update" in cls.__name__:
- obj, mutation = await cls.mutate_update(
- root=root, info=info, branch=context.branch, at=context.at, **kwargs
- )
+ obj, mutation = await cls.mutate_update(info=info, branch=context.branch, at=context.at, **kwargs)
action = MutationAction.UPDATED
elif "Upsert" in cls.__name__:
node_manager = NodeManager()
@@ -82,16 +77,14 @@ async def mutate(cls, root: dict, info: GraphQLResolveInfo, *args, **kwargs):
MutationNodeGetterByDefaultFilter(db=context.db, node_manager=node_manager),
]
obj, mutation, created = await cls.mutate_upsert(
- root=root, info=info, branch=context.branch, at=context.at, node_getters=node_getters, **kwargs
+ info=info, branch=context.branch, at=context.at, node_getters=node_getters, **kwargs
)
if created:
action = MutationAction.ADDED
else:
action = MutationAction.UPDATED
elif "Delete" in cls.__name__:
- obj, mutation = await cls.mutate_delete(
- root=root, info=info, branch=context.branch, at=context.at, **kwargs
- )
+ obj, mutation = await cls.mutate_delete(info=info, branch=context.branch, at=context.at, **kwargs)
action = MutationAction.REMOVED
else:
raise ValueError(
@@ -107,15 +100,16 @@ async def mutate(cls, root: dict, info: GraphQLResolveInfo, *args, **kwargs):
data = await obj.to_graphql(db=context.db, filter_sensitive=True)
- message = messages.EventNodeMutated(
+ event = NodeMutatedEvent(
branch=context.branch.name,
kind=obj._schema.kind,
node_id=obj.id,
data=data,
- action=action.value,
- meta=Meta(initiator_id=WORKER_IDENTITY, request_id=request_id),
+ action=action,
+ meta=EventMeta(initiator_id=WORKER_IDENTITY, request_id=request_id),
)
- context.background.add_task(services.send, message)
+
+ context.background.add_task(context.service.event.send, event)
return mutation
@@ -147,7 +141,6 @@ async def _refresh_for_profile_update(
@classmethod
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -206,7 +199,6 @@ async def mutate_create_to_graphql(cls, info: GraphQLResolveInfo, db: InfrahubDa
@retry_db_transaction(name="object_update")
async def mutate_update(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -285,7 +277,6 @@ async def mutate_update_to_graphql(
@retry_db_transaction(name="object_upsert")
async def mutate_upsert(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -308,26 +299,25 @@ async def mutate_upsert(
if node:
updated_obj, mutation = await cls.mutate_update(
- root=root, info=info, data=data, branch=branch, at=at, database=db, node=node
+ info=info, data=data, branch=branch, at=at, database=db, node=node
)
return updated_obj, mutation, False
# We need to convert the InputObjectType into a dict in order to remove hfid that isn't a valid input when creating the object
data_dict = dict(data)
if "hfid" in data:
del data_dict["hfid"]
- created_obj, mutation = await cls.mutate_create(root=root, info=info, data=data_dict, branch=branch, at=at)
+ created_obj, mutation = await cls.mutate_create(info=info, data=data_dict, branch=branch, at=at)
return created_obj, mutation, True
@classmethod
@retry_db_transaction(name="object_delete")
async def mutate_delete(
cls,
- root,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
at: str,
- ):
+ ) -> tuple[Node, Self]:
context: GraphqlContext = info.context
obj = await NodeManager.find_object(
diff --git a/backend/infrahub/graphql/mutations/menu.py b/backend/infrahub/graphql/mutations/menu.py
new file mode 100644
index 0000000000..158f753798
--- /dev/null
+++ b/backend/infrahub/graphql/mutations/menu.py
@@ -0,0 +1,103 @@
+from typing import TYPE_CHECKING, Any, Optional
+
+from graphene import InputObjectType, Mutation
+from graphql import GraphQLResolveInfo
+from typing_extensions import Self
+
+from infrahub.core.branch import Branch
+from infrahub.core.constants import RESTRICTED_NAMESPACES
+from infrahub.core.manager import NodeManager
+from infrahub.core.node import Node
+from infrahub.core.protocols import CoreMenuItem
+from infrahub.core.schema import NodeSchema
+from infrahub.database import InfrahubDatabase
+from infrahub.exceptions import ValidationError
+from infrahub.graphql.mutations.main import InfrahubMutationMixin
+
+from .main import InfrahubMutationOptions
+
+if TYPE_CHECKING:
+ from infrahub.graphql.initialization import GraphqlContext
+
+EXTENDED_RESTRICTED_NAMESPACES = RESTRICTED_NAMESPACES + ["Builtin"]
+
+
+def validate_namespace(data: InputObjectType) -> None:
+ namespace = data.get("namespace")
+ if isinstance(namespace, dict) and "value" in namespace:
+ namespace_value = str(namespace.get("value"))
+ if namespace_value in EXTENDED_RESTRICTED_NAMESPACES:
+ raise ValidationError(
+ input_value={"namespace": f"{namespace_value} is not valid, it's a restricted namespace"}
+ )
+
+
+class InfrahubCoreMenuMutation(InfrahubMutationMixin, Mutation):
+ @classmethod
+ def __init_subclass_with_meta__( # pylint: disable=arguments-differ
+ cls, schema: NodeSchema, _meta: Optional[Any] = None, **options: dict[str, Any]
+ ) -> None:
+ # Make sure schema is a valid NodeSchema Node Class
+ if not isinstance(schema, NodeSchema):
+ raise ValueError(f"You need to pass a valid NodeSchema in '{cls.__name__}.Meta', received '{schema}'")
+
+ if not _meta:
+ _meta = InfrahubMutationOptions(cls)
+ _meta.schema = schema
+
+ super().__init_subclass_with_meta__(_meta=_meta, **options)
+
+ @classmethod
+ async def mutate_create(
+ cls,
+ info: GraphQLResolveInfo,
+ data: InputObjectType,
+ branch: Branch,
+ at: str,
+ database: Optional[InfrahubDatabase] = None,
+ ) -> tuple[Node, Self]:
+ validate_namespace(data=data)
+
+ obj, result = await super().mutate_create(info=info, data=data, branch=branch, at=at)
+
+ return obj, result
+
+ @classmethod
+ async def mutate_update(
+ cls,
+ info: GraphQLResolveInfo,
+ data: InputObjectType,
+ branch: Branch,
+ at: str,
+ database: Optional[InfrahubDatabase] = None,
+ node: Optional[Node] = None,
+ ) -> tuple[Node, Self]:
+ context: GraphqlContext = info.context
+
+ obj = await NodeManager.find_object(
+ db=context.db, kind=CoreMenuItem, id=data.get("id"), hfid=data.get("hfid"), branch=branch, at=at
+ )
+ validate_namespace(data=data)
+
+ if obj.protected.value:
+ raise ValidationError(input_value="This object is protected, it can't be modified.")
+
+ obj, result = await super().mutate_update(info=info, data=data, branch=branch, at=at, node=obj) # type: ignore[assignment]
+ return obj, result # type: ignore[return-value]
+
+ @classmethod
+ async def mutate_delete(
+ cls,
+ info: GraphQLResolveInfo,
+ data: InputObjectType,
+ branch: Branch,
+ at: str,
+ ) -> tuple[Node, Self]:
+ context: GraphqlContext = info.context
+ obj = await NodeManager.find_object(
+ db=context.db, kind=CoreMenuItem, id=data.get("id"), hfid=data.get("hfid"), branch=branch, at=at
+ )
+ if obj.protected.value:
+ raise ValidationError(input_value="This object is protected, it can't be deleted.")
+
+ return await super().mutate_delete(info=info, data=data, branch=branch, at=at)
diff --git a/backend/infrahub/graphql/mutations/node_getter/by_default_filter.py b/backend/infrahub/graphql/mutations/node_getter/by_default_filter.py
index fc4c675418..f5f14cd240 100644
--- a/backend/infrahub/graphql/mutations/node_getter/by_default_filter.py
+++ b/backend/infrahub/graphql/mutations/node_getter/by_default_filter.py
@@ -12,7 +12,7 @@
class MutationNodeGetterByDefaultFilter(MutationNodeGetterInterface):
- def __init__(self, db: InfrahubDatabase, node_manager: NodeManager):
+ def __init__(self, db: InfrahubDatabase, node_manager: NodeManager) -> None:
self.db = db
self.node_manager = node_manager
diff --git a/backend/infrahub/graphql/mutations/node_getter/by_hfid.py b/backend/infrahub/graphql/mutations/node_getter/by_hfid.py
index 05ff717ea4..808a699600 100644
--- a/backend/infrahub/graphql/mutations/node_getter/by_hfid.py
+++ b/backend/infrahub/graphql/mutations/node_getter/by_hfid.py
@@ -13,7 +13,7 @@
class MutationNodeGetterByHfid(MutationNodeGetterInterface):
- def __init__(self, db: InfrahubDatabase, node_manager: NodeManager):
+ def __init__(self, db: InfrahubDatabase, node_manager: NodeManager) -> None:
self.db = db
self.node_manager = node_manager
diff --git a/backend/infrahub/graphql/mutations/node_getter/by_id.py b/backend/infrahub/graphql/mutations/node_getter/by_id.py
index 383db251b3..f307e7f436 100644
--- a/backend/infrahub/graphql/mutations/node_getter/by_id.py
+++ b/backend/infrahub/graphql/mutations/node_getter/by_id.py
@@ -12,7 +12,7 @@
class MutationNodeGetterById(MutationNodeGetterInterface):
- def __init__(self, db: InfrahubDatabase, node_manager: NodeManager):
+ def __init__(self, db: InfrahubDatabase, node_manager: NodeManager) -> None:
self.db = db
self.node_manager = node_manager
diff --git a/backend/infrahub/graphql/mutations/proposed_change.py b/backend/infrahub/graphql/mutations/proposed_change.py
index 32b7f287ef..449211140d 100644
--- a/backend/infrahub/graphql/mutations/proposed_change.py
+++ b/backend/infrahub/graphql/mutations/proposed_change.py
@@ -5,7 +5,7 @@
from infrahub import lock
from infrahub.core.branch import Branch
-from infrahub.core.constants import CheckType, InfrahubKind, ProposedChangeState, ValidatorConclusion
+from infrahub.core.constants import CheckType, GlobalPermissions, InfrahubKind, ProposedChangeState, ValidatorConclusion
from infrahub.core.diff.ipam_diff_parser import IpamDiffParser
from infrahub.core.manager import NodeManager
from infrahub.core.merge import BranchMerger
@@ -25,7 +25,7 @@
from .main import InfrahubMutationOptions
if TYPE_CHECKING:
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
class InfrahubProposedChangeMutation(InfrahubMutationMixin, Mutation):
@@ -45,7 +45,6 @@ def __init_subclass_with_meta__(cls, schema: NodeSchema = None, _meta=None, **op
@retry_db_transaction(name="proposed_change_create")
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -57,7 +56,7 @@ async def mutate_create(
async with db.start_transaction() as dbt:
proposed_change, result = await super().mutate_create(
- root=root, info=info, data=data, branch=branch, at=at, database=dbt
+ info=info, data=data, branch=branch, at=at, database=dbt
)
destination_branch = proposed_change.destination_branch.value
source_branch = await _get_source_branch(db=dbt, name=proposed_change.source_branch.value)
@@ -85,9 +84,8 @@ async def mutate_create(
@classmethod
@retry_db_transaction(name="proposed_change_update")
- async def mutate_update(
+ async def mutate_update( # pylint: disable=too-many-branches
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -97,6 +95,19 @@ async def mutate_update(
):
context: GraphqlContext = info.context
+ has_merge_permission = False
+ if context.account_session:
+ for permission_backend in registry.permission_backends:
+ if has_merge_permission := await permission_backend.has_permission(
+ db=context.db,
+ account_id=context.active_account_session.account_id,
+ permission=f"global:{GlobalPermissions.MERGE_PROPOSED_CHANGE.value}:allow",
+ branch=branch,
+ ):
+ break
+ else:
+ has_merge_permission = True
+
obj = await NodeManager.get_one_by_id_or_default_filter(
db=context.db,
kind=cls._meta.schema.kind,
@@ -114,10 +125,14 @@ async def mutate_update(
updated_state = ProposedChangeState(state_update)
state.validate_state_transition(updated_state)
+ # Check before starting a transaction, stopping in the middle of the transaction seems to break with memgraph
+ if updated_state == ProposedChangeState.MERGED and not has_merge_permission:
+ raise ValidationError("You do not have the permission to merge proposed changes")
+
merger: Optional[BranchMerger] = None
async with context.db.start_transaction() as dbt:
proposed_change, result = await super().mutate_update(
- root=root, info=info, data=data, branch=branch, at=at, database=dbt, node=obj
+ info=info, data=data, branch=branch, at=at, database=dbt, node=obj
)
if updated_state == ProposedChangeState.MERGED:
diff --git a/backend/infrahub/graphql/mutations/relationship.py b/backend/infrahub/graphql/mutations/relationship.py
index 1f14e944dc..c0ae39fbec 100644
--- a/backend/infrahub/graphql/mutations/relationship.py
+++ b/backend/infrahub/graphql/mutations/relationship.py
@@ -22,7 +22,7 @@
from infrahub.core.relationship import RelationshipManager
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
# pylint: disable=unused-argument,too-many-branches
diff --git a/backend/infrahub/graphql/mutations/repository.py b/backend/infrahub/graphql/mutations/repository.py
index 57be6fae76..2a5612d27b 100644
--- a/backend/infrahub/graphql/mutations/repository.py
+++ b/backend/infrahub/graphql/mutations/repository.py
@@ -23,7 +23,7 @@
from infrahub.core.branch import Branch
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
log = get_logger()
@@ -45,7 +45,6 @@ def __init_subclass_with_meta__(cls, schema: Optional[NodeSchema] = None, _meta=
@classmethod
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -56,7 +55,7 @@ async def mutate_create(
cleanup_payload(data)
# Create the object in the database
- obj, result = await super().mutate_create(root, info, data, branch, at)
+ obj, result = await super().mutate_create(info, data, branch, at)
obj = cast(CoreGenericRepository, obj)
# First check the connectivity to the remote repository
@@ -120,7 +119,6 @@ async def mutate_create(
@classmethod
async def mutate_update(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -142,7 +140,7 @@ async def mutate_update(
include_source=True,
)
if node.get_kind() != InfrahubKind.READONLYREPOSITORY:
- return await super().mutate_update(root, info, data, branch, at, database=context.db, node=node)
+ return await super().mutate_update(info, data, branch, at, database=context.db, node=node)
node = cast(CoreReadOnlyRepository, node)
current_commit = node.commit.value
@@ -154,7 +152,7 @@ async def mutate_update(
if data.ref and data.ref.value:
new_ref = data.ref.value
- obj, result = await super().mutate_update(root, info, data, branch, at, database=context.db, node=node)
+ obj, result = await super().mutate_update(info, data, branch, at, database=context.db, node=node)
obj = cast(CoreReadOnlyRepository, obj)
send_update_message = (new_commit and new_commit != current_commit) or (new_ref and new_ref != current_ref)
diff --git a/backend/infrahub/graphql/mutations/resource_manager.py b/backend/infrahub/graphql/mutations/resource_manager.py
index 2f116d612e..227a64b8d2 100644
--- a/backend/infrahub/graphql/mutations/resource_manager.py
+++ b/backend/infrahub/graphql/mutations/resource_manager.py
@@ -24,7 +24,7 @@
from infrahub.core.node.resource_manager.ip_prefix_pool import CoreIPPrefixPool
from infrahub.database import InfrahubDatabase
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
class IPPrefixPoolGetResourceInput(InputObjectType):
@@ -171,7 +171,6 @@ def __init_subclass_with_meta__( # pylint: disable=arguments-differ
@classmethod
async def mutate_create(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -197,12 +196,11 @@ async def mutate_create(
if data["start_range"].value > data["end_range"].value:
raise ValidationError(input_value="start_range can't be larger than end_range")
- return await super().mutate_create(root=root, info=info, data=data, branch=branch, at=at)
+ return await super().mutate_create(info=info, data=data, branch=branch, at=at)
@classmethod
async def mutate_update(
cls,
- root: dict,
info: GraphQLResolveInfo,
data: InputObjectType,
branch: Branch,
@@ -218,9 +216,9 @@ async def mutate_update(
async with context.db.start_transaction() as dbt:
number_pool, result = await super().mutate_update(
- root=root, info=info, data=data, branch=branch, at=at, database=dbt, node=node
+ info=info, data=data, branch=branch, at=at, database=dbt, node=node
)
- if number_pool.start_range.value > number_pool.end_range.value:
+ if number_pool.start_range.value > number_pool.end_range.value: # type: ignore[attr-defined]
raise ValidationError(input_value="start_range can't be larger than end_range")
return number_pool, result
diff --git a/backend/infrahub/graphql/mutations/schema.py b/backend/infrahub/graphql/mutations/schema.py
index bbdf32bbe3..9a7869ff93 100644
--- a/backend/infrahub/graphql/mutations/schema.py
+++ b/backend/infrahub/graphql/mutations/schema.py
@@ -19,7 +19,7 @@
from ..types import DropdownFields
if TYPE_CHECKING:
- from .. import GraphqlContext
+ from ..initialization import GraphqlContext
log = get_logger()
diff --git a/backend/infrahub/graphql/mutations/task.py b/backend/infrahub/graphql/mutations/task.py
index ec074f9fa2..9d49b1b3ad 100644
--- a/backend/infrahub/graphql/mutations/task.py
+++ b/backend/infrahub/graphql/mutations/task.py
@@ -18,7 +18,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
TaskConclusion = Enum.from_enum(PyTaskConclusion)
diff --git a/backend/infrahub/graphql/permissions.py b/backend/infrahub/graphql/permissions.py
new file mode 100644
index 0000000000..ada4c6d184
--- /dev/null
+++ b/backend/infrahub/graphql/permissions.py
@@ -0,0 +1,30 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from infrahub.core.registry import registry
+from infrahub.core.schema import GenericSchema
+from infrahub.permissions.report import report_schema_permissions
+
+if TYPE_CHECKING:
+ from infrahub.core.schema import MainSchemaTypes
+ from infrahub.database import InfrahubDatabase
+ from infrahub.graphql.initialization import GraphqlContext
+
+
+async def get_permissions(db: InfrahubDatabase, schema: MainSchemaTypes, context: GraphqlContext) -> dict[str, Any]:
+ schema_objects = [schema]
+ if isinstance(schema, GenericSchema):
+ for node_name in schema.used_by:
+ schema_objects.append(
+ registry.schema.get_node_schema(name=node_name, branch=context.branch, duplicate=False)
+ )
+
+ response: dict[str, Any] = {"count": len(schema_objects), "edges": []}
+
+ nodes = await report_schema_permissions(
+ db=db, schemas=schema_objects, branch=context.branch, account_session=context.active_account_session
+ )
+ response["edges"] = [{"node": node} for node in nodes]
+
+ return response
diff --git a/backend/infrahub/graphql/queries/__init__.py b/backend/infrahub/graphql/queries/__init__.py
index 25aa60ea1a..ca05880f36 100644
--- a/backend/infrahub/graphql/queries/__init__.py
+++ b/backend/infrahub/graphql/queries/__init__.py
@@ -1,4 +1,4 @@
-from .account import AccountToken
+from .account import AccountPermissions, AccountToken
from .branch import BranchQueryList
from .diff.diff import DiffSummary
from .internal import InfrahubInfo
@@ -10,16 +10,17 @@
from .task import Task
__all__ = [
+ "AccountPermissions",
"AccountToken",
"BranchQueryList",
"DiffSummary",
- "InfrahubInfo",
- "InfrahubSearchAnywhere",
- "InfrahubStatus",
"InfrahubIPAddressGetNextAvailable",
"InfrahubIPPrefixGetNextAvailable",
+ "InfrahubInfo",
"InfrahubResourcePoolAllocated",
"InfrahubResourcePoolUtilization",
+ "InfrahubSearchAnywhere",
+ "InfrahubStatus",
"Relationship",
"Task",
]
diff --git a/backend/infrahub/graphql/queries/account.py b/backend/infrahub/graphql/queries/account.py
index 17f9471494..792f868c02 100644
--- a/backend/infrahub/graphql/queries/account.py
+++ b/backend/infrahub/graphql/queries/account.py
@@ -5,6 +5,7 @@
from graphene import Field, Int, List, ObjectType, String
from infrahub_sdk.utils import extract_fields_first_node
+from infrahub.core import registry
from infrahub.core.manager import NodeManager
from infrahub.core.protocols import InternalAccountToken
from infrahub.exceptions import PermissionDeniedError
@@ -12,7 +13,8 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
+ from infrahub.permissions.constants import AssignedPermissions
class AccountTokenNode(ObjectType):
@@ -64,3 +66,101 @@ async def resolve_account_tokens(
AccountToken = Field(
AccountTokenEdges, resolver=resolve_account_tokens, limit=Int(required=False), offset=Int(required=False)
)
+
+
+class AccountGlobalPermissionNode(ObjectType):
+ id = Field(String, required=True)
+ name = Field(String, required=True)
+ action = Field(String, required=True)
+ decision = Field(String, required=True)
+ identifier = Field(String, required=True)
+
+
+class AccountObjectPermissionNode(ObjectType):
+ id = Field(String, required=True)
+ branch = Field(String, required=True)
+ namespace = Field(String, required=True)
+ name = Field(String, required=True)
+ action = Field(String, required=True)
+ decision = Field(String, required=True)
+ identifier = Field(String, required=True)
+
+
+class AccountGlobalPermissionEdge(ObjectType):
+ node = Field(AccountGlobalPermissionNode, required=True)
+
+
+class AccountObjectPermissionEdge(ObjectType):
+ node = Field(AccountObjectPermissionNode, required=True)
+
+
+class AccountGlobalPermissionEdges(ObjectType):
+ count = Field(Int, required=True)
+ edges = Field(List(of_type=AccountGlobalPermissionEdge, required=True), required=True)
+
+
+class AccountObjectPermissionEdges(ObjectType):
+ count = Field(Int, required=True)
+ edges = Field(List(of_type=AccountObjectPermissionEdge, required=True), required=True)
+
+
+class AccountPermissionsEdges(ObjectType):
+ global_permissions = Field(AccountGlobalPermissionEdges, required=False)
+ object_permissions = Field(AccountObjectPermissionEdges, required=False)
+
+
+async def resolve_account_permissions(
+ root: dict, # pylint: disable=unused-argument
+ info: GraphQLResolveInfo,
+) -> dict:
+ context: GraphqlContext = info.context
+
+ if not context.account_session:
+ raise ValueError("An account_session is mandatory to execute this query")
+
+ fields = await extract_fields_first_node(info)
+ permissions: AssignedPermissions = {"global_permissions": [], "object_permissions": []}
+ for permission_backend in registry.permission_backends:
+ backend_permissions = await permission_backend.load_permissions(
+ db=context.db, account_id=context.account_session.account_id, branch=context.branch
+ )
+ permissions["global_permissions"].extend(backend_permissions["global_permissions"])
+ permissions["object_permissions"].extend(backend_permissions["object_permissions"])
+
+ response: dict[str, dict[str, Any]] = {}
+ if "global_permissions" in fields:
+ global_list = permissions["global_permissions"]
+ response["global_permissions"] = {"count": len(global_list)}
+ response["global_permissions"]["edges"] = [
+ {
+ "node": {
+ "id": obj.id,
+ "name": obj.name,
+ "action": obj.action,
+ "decision": obj.decision,
+ "identifier": str(obj),
+ }
+ }
+ for obj in global_list
+ ]
+ if "object_permissions" in fields:
+ object_list = permissions["object_permissions"]
+ response["object_permissions"] = {"count": len(object_list)}
+ response["object_permissions"]["edges"] = [
+ {
+ "node": {
+ "id": obj.id,
+ "branch": obj.branch,
+ "namespace": obj.namespace,
+ "name": obj.name,
+ "action": obj.action,
+ "decision": obj.decision,
+ "identifier": str(obj),
+ }
+ }
+ for obj in object_list
+ ]
+ return response
+
+
+AccountPermissions = Field(AccountPermissionsEdges, resolver=resolve_account_permissions)
diff --git a/backend/infrahub/graphql/queries/diff/diff.py b/backend/infrahub/graphql/queries/diff/diff.py
index 92e2a2ac2f..344388a824 100644
--- a/backend/infrahub/graphql/queries/diff/diff.py
+++ b/backend/infrahub/graphql/queries/diff/diff.py
@@ -16,7 +16,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
GrapheneDiffActionEnum = GrapheneEnum.from_enum(DiffAction)
diff --git a/backend/infrahub/graphql/queries/diff/tree.py b/backend/infrahub/graphql/queries/diff/tree.py
index c5287b3737..1d4d5c0ccc 100644
--- a/backend/infrahub/graphql/queries/diff/tree.py
+++ b/backend/infrahub/graphql/queries/diff/tree.py
@@ -31,7 +31,7 @@
EnrichedDiffSingleRelationship,
)
from infrahub.database import InfrahubDatabase
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
GrapheneDiffActionEnum = GrapheneEnum.from_enum(DiffAction)
GrapheneCardinalityEnum = GrapheneEnum.from_enum(RelationshipCardinality)
diff --git a/backend/infrahub/graphql/queries/ipam.py b/backend/infrahub/graphql/queries/ipam.py
index c2b8e9a4b7..df27b364f2 100644
--- a/backend/infrahub/graphql/queries/ipam.py
+++ b/backend/infrahub/graphql/queries/ipam.py
@@ -15,7 +15,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class IPAddressGetNextAvailable(ObjectType):
diff --git a/backend/infrahub/graphql/queries/relationship.py b/backend/infrahub/graphql/queries/relationship.py
index 6d2312c0f0..40041f42a6 100644
--- a/backend/infrahub/graphql/queries/relationship.py
+++ b/backend/infrahub/graphql/queries/relationship.py
@@ -11,7 +11,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class Relationships(ObjectType):
diff --git a/backend/infrahub/graphql/queries/resource_manager.py b/backend/infrahub/graphql/queries/resource_manager.py
index 420734a038..9b75e5f826 100644
--- a/backend/infrahub/graphql/queries/resource_manager.py
+++ b/backend/infrahub/graphql/queries/resource_manager.py
@@ -24,7 +24,7 @@
from infrahub.core.node import Node
from infrahub.core.protocols import CoreNode
from infrahub.database import InfrahubDatabase
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class IPPoolUtilizationResource(ObjectType):
diff --git a/backend/infrahub/graphql/queries/search.py b/backend/infrahub/graphql/queries/search.py
index 831ac691b5..36f1c4273a 100644
--- a/backend/infrahub/graphql/queries/search.py
+++ b/backend/infrahub/graphql/queries/search.py
@@ -12,7 +12,7 @@
from graphql import GraphQLResolveInfo
from infrahub.core.protocols import CoreNode
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class Node(ObjectType):
diff --git a/backend/infrahub/graphql/queries/status.py b/backend/infrahub/graphql/queries/status.py
index d1f7c94093..971b6dbf68 100644
--- a/backend/infrahub/graphql/queries/status.py
+++ b/backend/infrahub/graphql/queries/status.py
@@ -10,7 +10,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class StatusSummary(ObjectType):
@@ -46,9 +46,7 @@ async def resolve_status(
service = context.service or services.service
fields = await extract_fields_first_node(info)
response: dict[str, Any] = {}
- workers = await service.component.list_workers(
- branch=context.branch.id if context.branch.id else context.branch.name, schema_hash=True
- )
+ workers = await service.component.list_workers(branch=context.branch.id or context.branch.name, schema_hash=True)
if summary := fields.get("summary"):
response["summary"] = {}
diff --git a/backend/infrahub/graphql/queries/task.py b/backend/infrahub/graphql/queries/task.py
index f669ddd386..713b9b2540 100644
--- a/backend/infrahub/graphql/queries/task.py
+++ b/backend/infrahub/graphql/queries/task.py
@@ -11,7 +11,7 @@
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class Tasks(ObjectType):
diff --git a/backend/infrahub/graphql/query.py b/backend/infrahub/graphql/query.py
index 0c815079f0..c049f82313 100644
--- a/backend/infrahub/graphql/query.py
+++ b/backend/infrahub/graphql/query.py
@@ -10,7 +10,7 @@
from infrahub.core.protocols import CoreGraphQLQuery
from infrahub.core.registry import registry
from infrahub.core.timestamp import Timestamp
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
if TYPE_CHECKING:
from graphql.execution import ExecutionResult
diff --git a/backend/infrahub/graphql/resolver.py b/backend/infrahub/graphql/resolver.py
index 99229140bd..820d25f8be 100644
--- a/backend/infrahub/graphql/resolver.py
+++ b/backend/infrahub/graphql/resolver.py
@@ -4,20 +4,44 @@
from infrahub_sdk.utils import extract_fields
-from infrahub.core.constants import BranchSupportType, RelationshipHierarchyDirection
+from infrahub.core.constants import BranchSupportType, InfrahubKind, RelationshipHierarchyDirection
from infrahub.core.manager import NodeManager
from infrahub.core.query.node import NodeGetHierarchyQuery
+from infrahub.exceptions import NodeNotFoundError
+from .parser import extract_selection
+from .permissions import get_permissions
from .types import RELATIONS_PROPERTY_MAP, RELATIONS_PROPERTY_MAP_REVERSED
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.core.schema import NodeSchema
- from infrahub.graphql import GraphqlContext
+ from infrahub.core.schema import MainSchemaTypes, NodeSchema
+ from infrahub.graphql.initialization import GraphqlContext
-async def default_resolver(*args, **kwargs):
+async def account_resolver(
+ root, # pylint: disable=unused-argument
+ info: GraphQLResolveInfo,
+) -> dict:
+ fields = await extract_fields(info.field_nodes[0].selection_set)
+ context: GraphqlContext = info.context
+
+ async with context.db.start_session() as db:
+ results = await NodeManager.query(
+ schema=InfrahubKind.GENERICACCOUNT,
+ filters={"ids": [context.account_session.account_id]},
+ fields=fields,
+ db=db,
+ )
+ if results:
+ account_profile = await results[0].to_graphql(db=db, fields=fields)
+ return account_profile
+
+ raise NodeNotFoundError(node_type=InfrahubKind.GENERICACCOUNT, identifier=context.account_session.account_id)
+
+
+async def default_resolver(*args: Any, **kwargs) -> dict | list[dict] | None:
"""Not sure why but the default resolver returns sometime 4 positional args and sometime 2.
When it returns 4, they are organized as follow
@@ -94,6 +118,71 @@ async def default_resolver(*args, **kwargs):
return await objs[0].to_graphql(db=db, fields=fields, related_node_ids=context.related_node_ids)
+async def default_paginated_list_resolver(
+ root: dict, # pylint: disable=unused-argument
+ info: GraphQLResolveInfo,
+ offset: int | None = None,
+ limit: int | None = None,
+ partial_match: bool = False,
+ **kwargs: dict[str, Any],
+) -> dict[str, Any]:
+ schema: MainSchemaTypes = info.return_type.graphene_type._meta.schema
+ fields = await extract_selection(info.field_nodes[0], schema=schema)
+
+ context: GraphqlContext = info.context
+ async with context.db.start_session() as db:
+ response: dict[str, Any] = {"edges": []}
+ filters = {
+ key: value for key, value in kwargs.items() if ("__" in key and value is not None) or key in ("ids", "hfid")
+ }
+
+ edges = fields.get("edges", {})
+ node_fields = edges.get("node", {})
+
+ permissions = fields.get("permissions")
+ if permissions:
+ response["permissions"] = await get_permissions(db=db, schema=schema, context=context)
+
+ objs = []
+ if edges or "hfid" in filters:
+ objs = await NodeManager.query(
+ db=db,
+ schema=schema,
+ filters=filters or None,
+ fields=node_fields,
+ at=context.at,
+ branch=context.branch,
+ limit=limit,
+ offset=offset,
+ account=context.account_session,
+ include_source=True,
+ include_owner=True,
+ partial_match=partial_match,
+ )
+
+ if "count" in fields:
+ if filters.get("hfid"):
+ response["count"] = len(objs)
+ else:
+ response["count"] = await NodeManager.count(
+ db=db,
+ schema=schema,
+ filters=filters,
+ at=context.at,
+ branch=context.branch,
+ partial_match=partial_match,
+ )
+
+ if objs:
+ objects = [
+ {"node": await obj.to_graphql(db=db, fields=node_fields, related_node_ids=context.related_node_ids)}
+ for obj in objs
+ ]
+ response["edges"] = objects
+
+ return response
+
+
async def single_relationship_resolver(parent: dict, info: GraphQLResolveInfo, **kwargs) -> dict[str, Any]:
"""Resolver for relationships of cardinality=one for Edged responses
diff --git a/backend/infrahub/graphql/schema.py b/backend/infrahub/graphql/schema.py
index c56cfac1f7..a43fe5d789 100644
--- a/backend/infrahub/graphql/schema.py
+++ b/backend/infrahub/graphql/schema.py
@@ -1,42 +1,44 @@
from __future__ import annotations
-from typing import TYPE_CHECKING
-
from graphene import ObjectType
-from infrahub_sdk.utils import extract_fields
-
-from infrahub.core.constants import InfrahubKind
-from infrahub.core.manager import NodeManager
-from infrahub.exceptions import NodeNotFoundError
-from .mutations import (
+from .mutations.account import (
+ InfrahubAccountSelfUpdate,
+ InfrahubAccountTokenCreate,
+ InfrahubAccountTokenDelete,
+)
+from .mutations.branch import (
BranchCreate,
BranchDelete,
BranchMerge,
BranchRebase,
BranchUpdate,
BranchValidate,
- DiffUpdateMutation,
- InfrahubAccountSelfUpdate,
- InfrahubAccountTokenCreate,
- InfrahubAccountTokenDelete,
- IPAddressPoolGetResource,
- IPPrefixPoolGetResource,
- ProcessRepository,
- ProposedChangeRequestRunCheck,
+)
+from .mutations.diff import DiffUpdateMutation
+from .mutations.diff_conflict import ResolveDiffConflict
+from .mutations.proposed_change import ProposedChangeRequestRunCheck
+from .mutations.relationship import (
RelationshipAdd,
RelationshipRemove,
- ResolveDiffConflict,
+)
+from .mutations.repository import (
+ ProcessRepository,
+ ValidateRepositoryConnectivity,
+)
+from .mutations.resource_manager import IPAddressPoolGetResource, IPPrefixPoolGetResource
+from .mutations.schema import (
SchemaDropdownAdd,
SchemaDropdownRemove,
SchemaEnumAdd,
SchemaEnumRemove,
+)
+from .mutations.task import (
TaskCreate,
TaskUpdate,
- ValidateRepositoryConnectivity,
)
-from .parser import extract_selection
from .queries import (
+ AccountPermissions,
AccountToken,
BranchQueryList,
DiffSummary,
@@ -52,42 +54,11 @@
)
from .queries.diff.tree import DiffTreeQuery, DiffTreeSummaryQuery
-if TYPE_CHECKING:
- from graphql import GraphQLResolveInfo
-
- from . import GraphqlContext
-
-
-# pylint: disable=unused-argument
-
-
-async def default_paginated_list_resolver(root: dict, info: GraphQLResolveInfo, **kwargs):
- fields = await extract_selection(info.field_nodes[0], schema=info.return_type.graphene_type._meta.schema)
-
- return await info.return_type.graphene_type.get_paginated_list(**kwargs, fields=fields, context=info.context)
-
-
-async def account_resolver(root, info: GraphQLResolveInfo):
- fields = await extract_fields(info.field_nodes[0].selection_set)
- context: GraphqlContext = info.context
-
- async with context.db.start_session() as db:
- results = await NodeManager.query(
- schema=InfrahubKind.GENERICACCOUNT,
- filters={"ids": [context.account_session.account_id]},
- fields=fields,
- db=db,
- )
- if results:
- account_profile = await results[0].to_graphql(db=db, fields=fields)
- return account_profile
-
- raise NodeNotFoundError(node_type=InfrahubKind.GENERICACCOUNT, identifier=context.account_session.account_id)
-
class InfrahubBaseQuery(ObjectType):
Branch = BranchQueryList
InfrahubAccountToken = AccountToken
+ InfrahubPermissions = AccountPermissions
DiffTree = DiffTreeQuery
DiffTreeSummary = DiffTreeSummaryQuery
diff --git a/backend/infrahub/graphql/subscription/graphql_query.py b/backend/infrahub/graphql/subscription/graphql_query.py
index 3eb1d6c536..20f866b4de 100644
--- a/backend/infrahub/graphql/subscription/graphql_query.py
+++ b/backend/infrahub/graphql/subscription/graphql_query.py
@@ -13,7 +13,7 @@
from infrahub.log import get_logger
if TYPE_CHECKING:
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
log = get_logger(name="infrahub.graphql")
diff --git a/backend/infrahub/graphql/types/__init__.py b/backend/infrahub/graphql/types/__init__.py
index c7c60dd640..9066c468a2 100644
--- a/backend/infrahub/graphql/types/__init__.py
+++ b/backend/infrahub/graphql/types/__init__.py
@@ -23,43 +23,43 @@
)
from .branch import BranchType
from .interface import InfrahubInterface
-from .mixin import GetListMixin
from .node import InfrahubObject
+from .permission import PaginatedObjectPermission
from .relationship import RelationshipNode
from .standard_node import InfrahubObjectType
from .task import TaskNodes
from .task_log import TaskLog, TaskLogEdge, TaskLogNodes
__all__ = [
+ "AnyAttributeType",
"AttributeInterface",
"BaseAttribute",
+ "BoolAttributeType",
+ "BranchType",
+ "CheckboxAttributeType",
"DropdownFields",
"DropdownType",
"IPHostType",
"IPNetworkType",
- "MacAddressType",
- "TextAttributeType",
- "NumberAttributeType",
- "CheckboxAttributeType",
- "StrAttributeType",
- "IntAttributeType",
- "BoolAttributeType",
- "ListAttributeType",
- "JSONAttributeType",
- "AnyAttributeType",
- "BranchType",
"InfrahubInterface",
- "GetListMixin",
"InfrahubObject",
"InfrahubObjectType",
+ "IntAttributeType",
+ "JSONAttributeType",
+ "ListAttributeType",
+ "MacAddressType",
+ "NumberAttributeType",
+ "PaginatedObjectPermission",
"RelatedIPAddressNodeInput",
"RelatedNodeInput",
"RelatedPrefixNodeInput",
"RelationshipNode",
+ "StrAttributeType",
"TaskLog",
"TaskLogEdge",
"TaskLogNodes",
"TaskNodes",
+ "TextAttributeType",
]
diff --git a/backend/infrahub/graphql/types/attribute.py b/backend/infrahub/graphql/types/attribute.py
index dcb0b4252d..3dfd2af491 100644
--- a/backend/infrahub/graphql/types/attribute.py
+++ b/backend/infrahub/graphql/types/attribute.py
@@ -1,5 +1,7 @@
from __future__ import annotations
+from typing import Any
+
from graphene import BigInt, Boolean, DateTime, Field, InputObjectType, Int, List, ObjectType, String
from graphene.types.generic import GenericScalar
@@ -70,7 +72,7 @@ class BaseAttribute(ObjectType):
is_from_profile = Field(Boolean)
@classmethod
- def __init_subclass__(cls, **kwargs):
+ def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:
super().__init_subclass__(**kwargs)
registry.default_graphql_type[cls.__name__] = cls
diff --git a/backend/infrahub/graphql/types/branch.py b/backend/infrahub/graphql/types/branch.py
index 296b05c927..9526afde54 100644
--- a/backend/infrahub/graphql/types/branch.py
+++ b/backend/infrahub/graphql/types/branch.py
@@ -10,7 +10,7 @@
from .standard_node import InfrahubObjectType
if TYPE_CHECKING:
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class BranchType(InfrahubObjectType):
diff --git a/backend/infrahub/graphql/types/enums.py b/backend/infrahub/graphql/types/enums.py
index 45e2f06521..df26aab8b9 100644
--- a/backend/infrahub/graphql/types/enums.py
+++ b/backend/infrahub/graphql/types/enums.py
@@ -5,3 +5,5 @@
CheckType = Enum.from_enum(constants.CheckType)
Severity = Enum.from_enum(constants.Severity)
+
+PermissionDecision = Enum.from_enum(constants.PermissionDecision)
diff --git a/backend/infrahub/graphql/types/interface.py b/backend/infrahub/graphql/types/interface.py
index 0c95000114..11433ba54f 100644
--- a/backend/infrahub/graphql/types/interface.py
+++ b/backend/infrahub/graphql/types/interface.py
@@ -5,12 +5,10 @@
from graphene import Interface
from graphene.types.interface import InterfaceOptions
-from .mixin import GetListMixin
-
if TYPE_CHECKING:
from graphql import GraphQLResolveInfo
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
from infrahub.graphql.types import InfrahubObject
@@ -18,7 +16,7 @@ class InfrahubInterfaceOptions(InterfaceOptions):
schema = None
-class InfrahubInterface(Interface, GetListMixin):
+class InfrahubInterface(Interface):
@classmethod
def resolve_type(cls, instance: dict[str, Any], info: GraphQLResolveInfo) -> InfrahubObject:
context: GraphqlContext = info.context
diff --git a/backend/infrahub/graphql/types/mixin.py b/backend/infrahub/graphql/types/mixin.py
deleted file mode 100644
index 6138a46b85..0000000000
--- a/backend/infrahub/graphql/types/mixin.py
+++ /dev/null
@@ -1,91 +0,0 @@
-from __future__ import annotations
-
-from typing import TYPE_CHECKING, Any
-
-from infrahub.core.manager import NodeManager
-
-if TYPE_CHECKING:
- from infrahub.graphql import GraphqlContext
-
-
-class GetListMixin:
- """Mixins to Query the list of nodes using the NodeManager."""
-
- @classmethod
- async def get_list(cls, fields: dict, context: GraphqlContext, **kwargs):
- async with context.db.start_session() as db:
- filters = {key: value for key, value in kwargs.items() if ("__" in key and value) or key in ("ids", "hfid")}
-
- objs = await NodeManager.query(
- db=db,
- schema=cls._meta.schema,
- filters=filters or None,
- fields=fields,
- at=context.at,
- branch=context.branch,
- account=context.account_session,
- include_source=True,
- include_owner=True,
- )
-
- if not objs:
- return []
- return [
- await obj.to_graphql(db=db, fields=fields, related_node_ids=context.related_node_ids) for obj in objs
- ]
-
- @classmethod
- async def get_paginated_list(cls, fields: dict, context: GraphqlContext, **kwargs):
- partial_match = kwargs.pop("partial_match", False)
-
- async with context.db.start_session() as db:
- response: dict[str, Any] = {"edges": []}
- offset = kwargs.pop("offset", None)
- limit = kwargs.pop("limit", None)
- filters = {
- key: value
- for key, value in kwargs.items()
- if ("__" in key and value is not None) or key in ("ids", "hfid")
- }
-
- edges = fields.get("edges", {})
- node_fields = edges.get("node", {})
-
- objs = []
- if edges or "hfid" in filters:
- objs = await NodeManager.query(
- db=db,
- schema=cls._meta.schema,
- filters=filters or None,
- fields=node_fields,
- at=context.at,
- branch=context.branch,
- limit=limit,
- offset=offset,
- account=context.account_session,
- include_source=True,
- include_owner=True,
- partial_match=partial_match,
- )
-
- if "count" in fields:
- if filters.get("hfid"):
- response["count"] = len(objs)
- else:
- response["count"] = await NodeManager.count(
- db=db,
- schema=cls._meta.schema,
- filters=filters,
- at=context.at,
- branch=context.branch,
- partial_match=partial_match,
- )
-
- if objs:
- objects = [
- {"node": await obj.to_graphql(db=db, fields=node_fields, related_node_ids=context.related_node_ids)}
- for obj in objs
- ]
- response["edges"] = objects
-
- return response
diff --git a/backend/infrahub/graphql/types/node.py b/backend/infrahub/graphql/types/node.py
index c4dda8eb40..f476692f73 100644
--- a/backend/infrahub/graphql/types/node.py
+++ b/backend/infrahub/graphql/types/node.py
@@ -7,14 +7,12 @@
from infrahub.core.schema import GenericSchema, MainSchemaTypes, NodeSchema, ProfileSchema
-from .mixin import GetListMixin
-
class InfrahubObjectOptions(ObjectTypeOptions):
- schema: Optional[MainSchemaTypes] = None
+ schema: MainSchemaTypes
-class InfrahubObject(ObjectType, GetListMixin):
+class InfrahubObject(ObjectType):
@classmethod
def __init_subclass_with_meta__( # pylint: disable=arguments-differ
cls,
diff --git a/backend/infrahub/graphql/types/permission.py b/backend/infrahub/graphql/types/permission.py
new file mode 100644
index 0000000000..2e92a1a12d
--- /dev/null
+++ b/backend/infrahub/graphql/types/permission.py
@@ -0,0 +1,26 @@
+from __future__ import annotations
+
+from graphene import Field, Int, List, ObjectType, String
+
+from .enums import PermissionDecision
+
+
+class ObjectPermission(ObjectType):
+ kind = Field(String, required=True, description="The kind this permission refers to.")
+ view = Field(PermissionDecision, required=True, description="Indicates if the account has the read permission")
+ create = Field(PermissionDecision, required=True, description="Indicates if the account has the create permission")
+ update = Field(PermissionDecision, required=True, description="Indicates if the account has the update permission")
+ delete = Field(PermissionDecision, required=True, description="Indicates if the account has the delete permission")
+
+
+class ObjectPermissionNode(ObjectType):
+ node = Field(ObjectPermission, required=True)
+
+
+class PaginatedObjectPermission(ObjectType):
+ count = Field(
+ Int,
+ required=True,
+ description="The number of permissions applicable, will be 1 for normal nodes or possibly more for generics",
+ )
+ edges = Field(List(of_type=ObjectPermissionNode, required=True), required=True)
diff --git a/backend/infrahub/graphql/types/standard_node.py b/backend/infrahub/graphql/types/standard_node.py
index 19ac68267a..28b25e0eea 100644
--- a/backend/infrahub/graphql/types/standard_node.py
+++ b/backend/infrahub/graphql/types/standard_node.py
@@ -8,7 +8,7 @@
from infrahub import config
if TYPE_CHECKING:
- from infrahub.graphql import GraphqlContext
+ from infrahub.graphql.initialization import GraphqlContext
class InfrahubObjectTypeOptions(ObjectTypeOptions):
@@ -19,7 +19,7 @@ class InfrahubObjectType(ObjectType):
@classmethod
def __init_subclass_with_meta__( # pylint: disable=arguments-differ
cls, model=None, interfaces=(), _meta=None, **options
- ):
+ ) -> None:
if not _meta:
_meta = InfrahubObjectTypeOptions(cls)
@@ -28,7 +28,7 @@ def __init_subclass_with_meta__( # pylint: disable=arguments-differ
super().__init_subclass_with_meta__(_meta=_meta, interfaces=interfaces, **options)
@classmethod
- async def get_list(cls, fields: dict[str, Any], context: GraphqlContext, **kwargs):
+ async def get_list(cls, fields: dict[str, Any], context: GraphqlContext, **kwargs) -> list[dict[str, Any]]:
async with context.db.session(database=config.SETTINGS.database.database_name) as db:
filters = {key: value for key, value in kwargs.items() if "__" in key and value}
diff --git a/backend/infrahub/graphql/utils.py b/backend/infrahub/graphql/utils.py
index e956fdd585..48b15de931 100644
--- a/backend/infrahub/graphql/utils.py
+++ b/backend/infrahub/graphql/utils.py
@@ -69,7 +69,7 @@ def selected_field_names_fast(
return selected_field_names(selection_set, context, runtime_type)
-def selected_field_names_naive(selection_set: SelectionSetNode):
+def selected_field_names_naive(selection_set: SelectionSetNode) -> list:
"""Get the list of field names that are selected at the current level. Does not include nested names.
Limitations:
@@ -179,7 +179,7 @@ def selected_field_names_from_context(
return (field.name.value for fields_list in fields_map.values() for field in fields_list)
-def print_query(info: GraphQLResolveInfo):
+def print_query(info: GraphQLResolveInfo) -> None:
"""Traverse the query"""
initial_selection_set = info.field_nodes[0].selection_set
print_selection_set(initial_selection_set, 1)
diff --git a/backend/infrahub/lock.py b/backend/infrahub/lock.py
index 787a867920..d8a37d96c2 100644
--- a/backend/infrahub/lock.py
+++ b/backend/infrahub/lock.py
@@ -45,7 +45,7 @@
class InfrahubMultiLock:
"""Context manager to allow multiple locks to be reserved together"""
- def __init__(self, _registry: InfrahubLockRegistry, locks: Optional[list[str]] = None):
+ def __init__(self, _registry: InfrahubLockRegistry, locks: Optional[list[str]] = None) -> None:
self.registry = _registry
self.locks = locks or []
@@ -72,7 +72,7 @@ async def release(self) -> None:
class NATSLock:
"""Context manager to lock using NATS"""
- def __init__(self, service: InfrahubServices, name: str):
+ def __init__(self, service: InfrahubServices, name: str) -> None:
self.name = name
self.token = None
self.service = service
@@ -118,7 +118,7 @@ def __init__(
connection: Optional[Union[redis.Redis, InfrahubServices]] = None,
local: Optional[bool] = None,
in_multi: bool = False,
- ):
+ ) -> None:
self.use_local: bool = local
self.local: LocalLock = None
self.remote: GlobalLock = None
@@ -175,7 +175,7 @@ async def locked(self) -> bool:
class InfrahubLockRegistry:
def __init__(
self, token: Optional[str] = None, local_only: bool = False, service: Optional[InfrahubServices] = None
- ):
+ ) -> None:
if config.SETTINGS.cache.enable and not local_only:
if config.SETTINGS.cache.driver == config.CacheDriver.Redis:
self.connection = redis.Redis(
@@ -256,6 +256,6 @@ async def wait_until_available(self, name: str) -> None:
await sleep(0.1)
-def initialize_lock(local_only: bool = False, service: Optional[InfrahubServices] = None):
+def initialize_lock(local_only: bool = False, service: Optional[InfrahubServices] = None) -> None:
global registry # pylint: disable=global-statement
registry = InfrahubLockRegistry(local_only=local_only, service=service)
diff --git a/sync/examples/ipfabric_to_infrahub/infrahub/__init__.py b/backend/infrahub/menu/__init__.py
similarity index 100%
rename from sync/examples/ipfabric_to_infrahub/infrahub/__init__.py
rename to backend/infrahub/menu/__init__.py
diff --git a/backend/infrahub/menu/constants.py b/backend/infrahub/menu/constants.py
new file mode 100644
index 0000000000..e0040eb425
--- /dev/null
+++ b/backend/infrahub/menu/constants.py
@@ -0,0 +1,10 @@
+from infrahub.utils import InfrahubStringEnum
+
+
+class MenuSection(InfrahubStringEnum):
+ OBJECT = "object"
+ INTERNAL = "internal"
+
+
+DEFAULT_MENU = "Other"
+FULL_DEFAULT_MENU = "Builtin:Other"
diff --git a/backend/infrahub/menu/generator.py b/backend/infrahub/menu/generator.py
new file mode 100644
index 0000000000..485d3dbf52
--- /dev/null
+++ b/backend/infrahub/menu/generator.py
@@ -0,0 +1,101 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from infrahub.core import registry
+from infrahub.core.branch import Branch # noqa: TCH001
+from infrahub.core.protocols import CoreMenuItem
+from infrahub.log import get_logger
+
+from .constants import FULL_DEFAULT_MENU
+from .models import MenuDict, MenuItemDict
+
+if TYPE_CHECKING:
+ from infrahub.auth import AccountSession
+ from infrahub.database import InfrahubDatabase
+
+log = get_logger()
+
+
+def get_full_name(obj: CoreMenuItem) -> str:
+ return f"{obj.namespace.value}:{obj.name.value}"
+
+
+# pylint: disable=too-many-branches
+async def generate_menu(
+ db: InfrahubDatabase, branch: Branch, menu_items: list[CoreMenuItem], account: AccountSession | None = None
+) -> MenuDict:
+ # FIXME temp hack to avoid pylint to complain
+ account = account # noqa: PLW0127
+
+ structure = MenuDict()
+ full_schema = registry.schema.get_full(branch=branch, duplicate=False)
+
+ already_processed = []
+ havent_been_processed = []
+
+ # Process the parent first
+ for item in menu_items:
+ full_name = get_full_name(item)
+ parent = await item.parent.get_peer(db=db, peer_type=CoreMenuItem)
+ if parent:
+ havent_been_processed.append(full_name)
+ continue
+ structure.data[full_name] = MenuItemDict.from_node(obj=item)
+ already_processed.append(full_name)
+
+ # Process the children
+ havent_been_processed = []
+ for item in menu_items:
+ full_name = get_full_name(item)
+ if full_name in already_processed:
+ continue
+
+ parent = await item.parent.get_peer(db=db, peer_type=CoreMenuItem)
+ if not parent:
+ havent_been_processed.append(full_name)
+ continue
+
+ parent_full_name = get_full_name(parent)
+ menu_item = structure.find_item(name=parent_full_name)
+ if menu_item:
+ child_item = MenuItemDict.from_node(obj=item)
+ menu_item.children[child_item.identifier] = child_item
+ else:
+ log.warning(
+ "new_menu_request: unable to find the parent menu item",
+ branch=branch.name,
+ menu_item=item.name.value,
+ parent_item=parent.name.value,
+ )
+
+ default_menu = structure.find_item(name=FULL_DEFAULT_MENU)
+ if not default_menu:
+ raise ValueError("Unable to locate the default menu item")
+
+ for schema in full_schema.values():
+ if schema.include_in_menu is False:
+ continue
+
+ menu_item = MenuItemDict.from_schema(model=schema)
+ already_in_schema = bool(structure.find_item(name=menu_item.identifier))
+ if already_in_schema:
+ continue
+
+ if schema.menu_placement:
+ menu_placement = structure.find_item(name=schema.menu_placement)
+
+ if menu_placement:
+ menu_placement.children[menu_item.identifier] = menu_item
+ continue
+
+ log.warning(
+ "new_menu_request: unable to find the menu_placement defined in the schema",
+ branch=branch.name,
+ item=schema.kind,
+ menu_placement=schema.menu_placement,
+ )
+
+ default_menu.children[menu_item.identifier] = menu_item
+
+ return structure
diff --git a/backend/infrahub/menu/menu.py b/backend/infrahub/menu/menu.py
new file mode 100644
index 0000000000..ba7d554aa8
--- /dev/null
+++ b/backend/infrahub/menu/menu.py
@@ -0,0 +1,255 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from infrahub.core.constants import infrahubkind as InfrahubKind
+from infrahub.core.schema import SchemaRoot, core_models
+
+from .constants import DEFAULT_MENU, MenuSection
+from .models import MenuItemDefinition
+
+if TYPE_CHECKING:
+ from infrahub.core.schema import MainSchemaTypes
+
+
+infrahub_schema = SchemaRoot(**core_models)
+
+
+def _extract_node_icon(model: MainSchemaTypes) -> str:
+ if not model.icon:
+ return ""
+ return model.icon
+
+
+default_menu = [
+ MenuItemDefinition(
+ namespace="Builtin",
+ name=DEFAULT_MENU,
+ label=DEFAULT_MENU.title(),
+ protected=True,
+ section=MenuSection.OBJECT,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="ObjectManagement",
+ label="Object Management",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ children=[
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Groups",
+ label="Groups",
+ kind=InfrahubKind.GENERICGROUP,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.GENERICGROUP)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Profiles",
+ label="Profiles",
+ kind=InfrahubKind.PROFILE,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.PROFILE)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=2000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="ResourceManager",
+ label="Resource Manager",
+ path="/resource-manager",
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.RESOURCEPOOL)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=3000,
+ ),
+ ],
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="ChangeControl",
+ label="Change Control",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=2000,
+ children=[
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Branches",
+ label="Branches",
+ path="/branche",
+ icon="mdi:layers-triple",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="ProposedChanges",
+ label="Proposed Changes",
+ path="/proposed-changes",
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.PROPOSEDCHANGE)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=2000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="CheckDefinition",
+ label="Check Definition",
+ kind=InfrahubKind.CHECKDEFINITION,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CHECKDEFINITION)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=3000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Tasks",
+ label="Tasks",
+ path="/tasks",
+ icon="mdi:shield-check",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=3000,
+ ),
+ ],
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="UnifiedStorage",
+ label="Unified Storage",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=3000,
+ children=[
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Schema",
+ label="Schema",
+ path="/schema",
+ icon="mdi:file-code",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Repository",
+ label="Repository",
+ kind=InfrahubKind.GENERICREPOSITORY,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.GENERICREPOSITORY)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=2000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="GraphqlQuery",
+ label="GraphQL Query",
+ kind=InfrahubKind.GRAPHQLQUERY,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.GRAPHQLQUERY)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=3000,
+ ),
+ ],
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Admin",
+ label="Admin",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=3000,
+ children=[
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="RoleManagement",
+ label="Role Management",
+ path="/role-management",
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.BASEPERMISSION)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Credentials",
+ label="Credentials",
+ kind=InfrahubKind.CREDENTIAL,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CREDENTIAL)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=2000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="Webhooks",
+ label="Webhooks",
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CUSTOMWEBHOOK)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=3000,
+ children=[
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="WebhookStandard",
+ label="Webhook",
+ kind=InfrahubKind.STANDARDWEBHOOK,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.STANDARDWEBHOOK)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ ),
+ MenuItemDefinition(
+ namespace="Builtin",
+ name="WebhookCustom",
+ label="Custom Webhook",
+ kind=InfrahubKind.CUSTOMWEBHOOK,
+ icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CUSTOMWEBHOOK)),
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=2000,
+ ),
+ ],
+ ),
+ ],
+ ),
+]
+
+
+# deployment = InterfaceMenu(
+# title="Deployment",
+# children=[
+# InterfaceMenu(
+# title="Artifact",
+# kind=InfrahubKind.ARTIFACT}",
+# icon=_extract_node_icon(full_schema[InfrahubKind.ARTIFACT]),
+# ),
+# InterfaceMenu(
+# title="Artifact Definition",
+# kind=InfrahubKind.ARTIFACTDEFINITION}",
+# icon=_extract_node_icon(full_schema[InfrahubKind.ARTIFACTDEFINITION]),
+# ),
+# InterfaceMenu(
+# title="Generator Definition",
+# kind=InfrahubKind.GENERATORDEFINITION}",
+# icon=_extract_node_icon(full_schema[InfrahubKind.GENERATORDEFINITION]),
+# ),
+# InterfaceMenu(
+# title="Generator Instance",
+# kind=InfrahubKind.GENERATORINSTANCE}",
+# icon=_extract_node_icon(full_schema[InfrahubKind.GENERATORINSTANCE]),
+# ),
+# InterfaceMenu(
+# title="Transformation",
+# kind=InfrahubKind.TRANSFORM}",
+# icon=_extract_node_icon(full_schema[InfrahubKind.TRANSFORM]),
+# ),
+# ],
+# )
diff --git a/backend/infrahub/menu/models.py b/backend/infrahub/menu/models.py
new file mode 100644
index 0000000000..9d68cd859b
--- /dev/null
+++ b/backend/infrahub/menu/models.py
@@ -0,0 +1,159 @@
+from __future__ import annotations
+
+from dataclasses import dataclass, field
+from typing import TYPE_CHECKING, Self
+
+from pydantic import BaseModel, Field
+
+from infrahub.core.node import Node
+from infrahub.core.protocols import CoreMenuItem
+from infrahub.core.schema import GenericSchema, MainSchemaTypes, NodeSchema, ProfileSchema
+
+from .constants import MenuSection
+
+if TYPE_CHECKING:
+ from infrahub.database import InfrahubDatabase
+
+
+def get_full_name(obj: CoreMenuItem | NodeSchema | GenericSchema | ProfileSchema) -> str:
+ if isinstance(obj, (NodeSchema, GenericSchema, ProfileSchema)):
+ return _get_full_name_schema(obj)
+ return _get_full_name_node(obj)
+
+
+def _get_full_name_node(obj: CoreMenuItem) -> str:
+ return f"{obj.namespace.value}:{obj.name.value}"
+
+
+def _get_full_name_schema(node: MainSchemaTypes) -> str:
+ return f"{node.namespace}:{node.name}"
+
+
+@dataclass
+class MenuDict:
+ data: dict[str, MenuItemDict] = field(default_factory=dict)
+
+ def find_item(self, name: str) -> MenuItemDict | None:
+ return self._find_child_item(name=name, children=self.data)
+
+ @classmethod
+ def _find_child_item(cls, name: str, children: dict[str, MenuItemDict]) -> MenuItemDict | None:
+ if name in children.keys():
+ return children[name]
+
+ for child in children.values():
+ if not child.children:
+ continue
+ found = cls._find_child_item(name=name, children=child.children)
+ if found:
+ return found
+ return None
+
+ def to_rest(self) -> Menu:
+ data: dict[str, list[MenuItemList]] = {}
+
+ for section in [MenuSection.INTERNAL, MenuSection.OBJECT]:
+ item_per_section = [value.to_list() for key, value in self.data.items() if value.section == section]
+ data[section.value] = sorted(item_per_section, key=lambda d: d.order_weight)
+
+ return Menu(sections=data)
+
+ # @staticmethod
+ # def _sort_menu_items(items: dict[str, MenuItem]) -> dict[str, MenuItem]:
+ # sorted_dict = dict(sorted(items.items(), key=lambda x: (x[1].order_weight, x[0]), reverse=False))
+ # return sorted_dict
+
+
+@dataclass
+class Menu:
+ sections: dict[str, list[MenuItemList]] = field(default_factory=dict)
+
+
+class MenuItem(BaseModel):
+ identifier: str = Field(..., description="Unique identifier for this menu item")
+ title: str = Field(..., description="Title of the menu item")
+ path: str = Field(default="", description="URL endpoint if applicable")
+ icon: str = Field(default="", description="The icon to show for the current view")
+ kind: str = Field(default="", description="Kind of the model associated with this menuitem if applicable")
+ order_weight: int = 5000
+ section: MenuSection = MenuSection.OBJECT
+
+ @classmethod
+ def from_node(cls, obj: CoreMenuItem) -> Self:
+ return cls(
+ identifier=get_full_name(obj),
+ title=obj.label.value or "",
+ icon=obj.icon.value or "",
+ order_weight=obj.order_weight.value,
+ path=obj.path.value or "",
+ kind=obj.get_kind(),
+ section=obj.section.value,
+ )
+
+ @classmethod
+ def from_schema(cls, model: NodeSchema | GenericSchema | ProfileSchema) -> Self:
+ return cls(
+ identifier=get_full_name(model),
+ title=model.label or model.kind,
+ path=f"/objects/{model.kind}",
+ icon=model.icon or "",
+ kind=model.kind,
+ )
+
+
+class MenuItemDict(MenuItem):
+ children: dict[str, MenuItemDict] = Field(default_factory=dict, description="Child objects")
+
+ def to_list(self) -> MenuItemList:
+ data = self.model_dump(exclude={"children"})
+ unsorted_children = [child.to_list() for child in self.children.values()]
+ data["children"] = sorted(unsorted_children, key=lambda d: d.order_weight)
+ return MenuItemList(**data)
+
+
+class MenuItemList(MenuItem):
+ children: list[MenuItemList] = Field(default_factory=list, description="Child objects")
+
+
+class MenuItemDefinition(BaseModel):
+ namespace: str
+ name: str
+ label: str
+ description: str = ""
+ icon: str = ""
+ protected: bool = False
+ path: str = ""
+ kind: str = ""
+ section: MenuSection = MenuSection.OBJECT
+ order_weight: int = 2000
+ children: list[MenuItemDefinition] = Field(default_factory=list)
+
+ async def to_node(self, db: InfrahubDatabase, parent: CoreMenuItem | None = None) -> CoreMenuItem:
+ obj = await Node.init(db=db, schema=CoreMenuItem)
+ await obj.new(
+ db=db,
+ namespace=self.namespace,
+ name=self.name,
+ label=self.label,
+ path=self.get_path(),
+ description=self.description or None,
+ icon=self.icon or None,
+ protected=self.protected,
+ section=self.section.value,
+ order_weight=self.order_weight,
+ parent=parent.id if parent else None,
+ )
+ return obj
+
+ def get_path(self) -> str | None:
+ if self.path:
+ return self.path
+
+ if self.kind:
+ return f"/objects/{self.kind}"
+
+ return None
+
+ @property
+ def full_name(self) -> str:
+ return f"{self.namespace}:{self.name}"
diff --git a/backend/infrahub/message_bus/messages/schema_migration_path.py b/backend/infrahub/message_bus/messages/schema_migration_path.py
index 364cc44e2e..c477b0346b 100644
--- a/backend/infrahub/message_bus/messages/schema_migration_path.py
+++ b/backend/infrahub/message_bus/messages/schema_migration_path.py
@@ -2,7 +2,7 @@
from typing import Optional
-from pydantic import Field
+from pydantic import BaseModel, Field
from infrahub.core.branch import Branch # noqa: TCH001
from infrahub.core.path import SchemaPath # noqa: TCH001
@@ -12,7 +12,7 @@
ROUTING_KEY = "schema.migration.path"
-class SchemaMigrationPath(InfrahubMessage):
+class SchemaMigrationPathData(BaseModel):
branch: Branch = Field(..., description="The name of the branch to target")
migration_name: str = Field(..., description="The name of the migration to run")
new_node_schema: Optional[MainSchemaTypes] = Field(None, description="new Schema of Node or Generic to process")
@@ -22,6 +22,10 @@ class SchemaMigrationPath(InfrahubMessage):
schema_path: SchemaPath = Field(..., description="SchemaPath to the element of the schema to migrate")
+class SchemaMigrationPath(SchemaMigrationPathData, InfrahubMessage):
+ pass
+
+
class SchemaMigrationPathResponseData(InfrahubResponseData):
errors: list[str] = Field(default_factory=list)
migration_name: Optional[str] = None
diff --git a/backend/infrahub/message_bus/messages/schema_validator_path.py b/backend/infrahub/message_bus/messages/schema_validator_path.py
index 277c781f36..07215e601d 100644
--- a/backend/infrahub/message_bus/messages/schema_validator_path.py
+++ b/backend/infrahub/message_bus/messages/schema_validator_path.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from pydantic import Field
+from pydantic import BaseModel, Field
from infrahub.core.branch import Branch # noqa: TCH001
from infrahub.core.path import SchemaPath # noqa: TCH001
@@ -11,13 +11,17 @@
ROUTING_KEY = "schema.validator.path"
-class SchemaValidatorPath(InfrahubMessage):
+class SchemaValidatorPathData(BaseModel):
branch: Branch = Field(..., description="The name of the branch to target")
constraint_name: str = Field(..., description="The name of the constraint to validate")
node_schema: MainSchemaTypes = Field(..., description="Schema of Node or Generic to validate")
schema_path: SchemaPath = Field(..., description="SchemaPath to the element of the schema to validate")
+class SchemaValidatorPath(SchemaValidatorPathData, InfrahubMessage):
+ pass
+
+
class SchemaValidatorPathResponseData(InfrahubResponseData):
violations: list[SchemaViolation] = Field(default_factory=list)
constraint_name: str
diff --git a/backend/infrahub/message_bus/messages/send_webhook_event.py b/backend/infrahub/message_bus/messages/send_webhook_event.py
index 9ee4284ae0..d3eda2f61d 100644
--- a/backend/infrahub/message_bus/messages/send_webhook_event.py
+++ b/backend/infrahub/message_bus/messages/send_webhook_event.py
@@ -1,11 +1,15 @@
-from pydantic import Field
+from pydantic import BaseModel, Field
from infrahub.message_bus import InfrahubMessage
-class SendWebhookEvent(InfrahubMessage):
+class SendWebhookData(BaseModel):
"""Sent a webhook to an external source."""
webhook_id: str = Field(..., description="The unique ID of the webhook")
event_type: str = Field(..., description="The event type")
event_data: dict = Field(..., description="The data tied to the event")
+
+
+class SendWebhookEvent(SendWebhookData, InfrahubMessage):
+ """Sent a webhook to an external source."""
diff --git a/backend/infrahub/message_bus/messages/transform_jinja_template.py b/backend/infrahub/message_bus/messages/transform_jinja_template.py
index 96cea8da17..00e6816fcc 100644
--- a/backend/infrahub/message_bus/messages/transform_jinja_template.py
+++ b/backend/infrahub/message_bus/messages/transform_jinja_template.py
@@ -1,13 +1,13 @@
from typing import Optional
-from pydantic import Field
+from pydantic import BaseModel, Field
from infrahub.message_bus import InfrahubMessage, InfrahubResponse, InfrahubResponseData
ROUTING_KEY = "transform.jinja.template"
-class TransformJinjaTemplate(InfrahubMessage):
+class TransformJinjaTemplateData(BaseModel):
"""Sent to trigger the checks for a repository to be executed."""
repository_id: str = Field(..., description="The unique ID of the Repository")
@@ -19,6 +19,10 @@ class TransformJinjaTemplate(InfrahubMessage):
commit: str = Field(..., description="The commit id to use when rendering the template")
+class TransformJinjaTemplate(TransformJinjaTemplateData, InfrahubMessage):
+ """Sent to trigger the checks for a repository to be executed."""
+
+
class TransformJinjaTemplateResponseData(InfrahubResponseData):
rendered_template: Optional[str] = Field(None, description="Rendered template in string format")
diff --git a/backend/infrahub/message_bus/operations/__init__.py b/backend/infrahub/message_bus/operations/__init__.py
index 91a159879d..7ab85d987c 100644
--- a/backend/infrahub/message_bus/operations/__init__.py
+++ b/backend/infrahub/message_bus/operations/__init__.py
@@ -1,6 +1,7 @@
from typing import Optional
import ujson
+from prefect import Flow
from infrahub.message_bus import RPCErrorResponse, messages
from infrahub.message_bus.operations import (
@@ -81,12 +82,17 @@
}
-async def execute_message(routing_key: str, message_body: bytes, service: InfrahubServices) -> Optional[MessageTTL]:
+async def execute_message(
+ routing_key: str, message_body: bytes, service: InfrahubServices, skip_flow: bool = False
+) -> Optional[MessageTTL]:
message_data = ujson.loads(message_body)
message = messages.MESSAGE_MAP[routing_key](**message_data)
message.set_log_data(routing_key=routing_key)
try:
- await COMMAND_MAP[routing_key](message=message, service=service)
+ func = COMMAND_MAP[routing_key]
+ if skip_flow and isinstance(func, Flow):
+ func = func.fn
+ await func(message=message, service=service)
except Exception as exc: # pylint: disable=broad-except
if message.reply_requested:
response = RPCErrorResponse(errors=[str(exc)], initial_message=message.model_dump())
diff --git a/backend/infrahub/message_bus/operations/check/artifact.py b/backend/infrahub/message_bus/operations/check/artifact.py
index cd579f186d..191d6db6ca 100644
--- a/backend/infrahub/message_bus/operations/check/artifact.py
+++ b/backend/infrahub/message_bus/operations/check/artifact.py
@@ -1,5 +1,7 @@
from typing import Union
+from prefect import flow
+
from infrahub.core.constants import InfrahubKind, ValidatorConclusion
from infrahub.core.timestamp import Timestamp
from infrahub.git.repository import InfrahubReadOnlyRepository, InfrahubRepository
@@ -12,7 +14,8 @@
log = get_logger()
-async def create(message: messages.CheckArtifactCreate, service: InfrahubServices):
+@flow(name="git-repository-check-artifact-create")
+async def create(message: messages.CheckArtifactCreate, service: InfrahubServices) -> None:
log.debug("Creating artifact", message=message)
validator = await service.client.get(
kind=InfrahubKind.ARTIFACTVALIDATOR, id=message.validator_id, include=["checks"]
diff --git a/backend/infrahub/message_bus/operations/check/generator.py b/backend/infrahub/message_bus/operations/check/generator.py
index 4b2cb7b41f..5ffcffa05f 100644
--- a/backend/infrahub/message_bus/operations/check/generator.py
+++ b/backend/infrahub/message_bus/operations/check/generator.py
@@ -3,6 +3,7 @@
from infrahub_sdk import InfrahubNode
from infrahub_sdk.exceptions import ModuleImportError
from infrahub_sdk.schema import InfrahubGeneratorDefinitionConfig
+from prefect import flow
from infrahub import lock
from infrahub.core.constants import GeneratorInstanceStatus, InfrahubKind, ValidatorConclusion
@@ -16,7 +17,8 @@
# pylint: disable=duplicate-code
-async def run(message: messages.CheckGeneratorRun, service: InfrahubServices):
+@flow(name="git-repository-check-generator-run")
+async def run(message: messages.CheckGeneratorRun, service: InfrahubServices) -> None:
repository = await get_initialized_repo(
repository_id=message.repository_id,
name=message.repository_name,
diff --git a/backend/infrahub/message_bus/operations/check/repository.py b/backend/infrahub/message_bus/operations/check/repository.py
index c361f28e68..9809c6326f 100644
--- a/backend/infrahub/message_bus/operations/check/repository.py
+++ b/backend/infrahub/message_bus/operations/check/repository.py
@@ -1,6 +1,7 @@
from typing import List
from infrahub_sdk import UUIDT
+from prefect import flow
from infrahub import lock
from infrahub.core.constants import InfrahubKind
@@ -16,7 +17,8 @@
log = get_logger()
-async def check_definition(message: messages.CheckRepositoryCheckDefinition, service: InfrahubServices):
+@flow(name="git-repository-check-definition")
+async def check_definition(message: messages.CheckRepositoryCheckDefinition, service: InfrahubServices) -> None:
definition = await service.client.get(
kind=InfrahubKind.CHECKDEFINITION, id=message.check_definition_id, branch=message.branch_name
)
@@ -141,7 +143,8 @@ async def check_definition(message: messages.CheckRepositoryCheckDefinition, ser
await service.send(message=event)
-async def merge_conflicts(message: messages.CheckRepositoryMergeConflicts, service: InfrahubServices):
+@flow(name="git-repository-check-merge-conflict")
+async def merge_conflicts(message: messages.CheckRepositoryMergeConflicts, service: InfrahubServices) -> None:
"""Runs a check to see if there are merge conflicts between two branches."""
log.info(
"Checking for merge conflicts",
@@ -222,7 +225,8 @@ async def merge_conflicts(message: messages.CheckRepositoryMergeConflicts, servi
)
-async def user_check(message: messages.CheckRepositoryUserCheck, service: InfrahubServices):
+@flow(name="git-repository-user-check")
+async def user_check(message: messages.CheckRepositoryUserCheck, service: InfrahubServices) -> None:
validator = await service.client.get(kind=InfrahubKind.USERVALIDATOR, id=message.validator_id)
await validator.checks.fetch()
diff --git a/backend/infrahub/message_bus/operations/event/branch.py b/backend/infrahub/message_bus/operations/event/branch.py
index e452df653e..b683b7c3bf 100644
--- a/backend/infrahub/message_bus/operations/event/branch.py
+++ b/backend/infrahub/message_bus/operations/event/branch.py
@@ -1,5 +1,7 @@
from typing import List
+from prefect import flow
+
from infrahub.core import registry
from infrahub.core.diff.model.path import BranchTrackingId
from infrahub.core.diff.repository.repository import DiffRepository
@@ -11,6 +13,7 @@
log = get_logger()
+@flow(name="event-branch-create")
async def create(message: messages.EventBranchCreate, service: InfrahubServices) -> None:
log.info("run_message", branch=message.branch)
@@ -23,6 +26,7 @@ async def create(message: messages.EventBranchCreate, service: InfrahubServices)
await service.send(message=event)
+@flow(name="event-branch-delete")
async def delete(message: messages.EventBranchDelete, service: InfrahubServices) -> None:
log.info("Branch was deleted", branch=message.branch)
@@ -36,6 +40,7 @@ async def delete(message: messages.EventBranchDelete, service: InfrahubServices)
await service.send(message=event)
+@flow(name="branch-event-merge")
async def merge(message: messages.EventBranchMerge, service: InfrahubServices) -> None:
log.info("Branch merged", source_branch=message.source_branch, target_branch=message.target_branch)
@@ -64,6 +69,7 @@ async def merge(message: messages.EventBranchMerge, service: InfrahubServices) -
await service.send(message=event)
+@flow(name="event-branch-rebased")
async def rebased(message: messages.EventBranchRebased, service: InfrahubServices) -> None:
log.info("Branch rebased", branch=message.branch)
diff --git a/backend/infrahub/message_bus/operations/event/node.py b/backend/infrahub/message_bus/operations/event/node.py
index d123fb33cd..8f9bbc51a6 100644
--- a/backend/infrahub/message_bus/operations/event/node.py
+++ b/backend/infrahub/message_bus/operations/event/node.py
@@ -1,5 +1,7 @@
from typing import List
+from prefect import flow
+
from infrahub.core.constants import InfrahubKind
from infrahub.log import get_logger
from infrahub.message_bus import InfrahubMessage, messages
@@ -8,6 +10,7 @@
log = get_logger()
+@flow(name="event-node-mutated")
async def mutated(
message: messages.EventNodeMutated,
service: InfrahubServices,
diff --git a/backend/infrahub/message_bus/operations/event/schema.py b/backend/infrahub/message_bus/operations/event/schema.py
index f84918d096..4bf27075a7 100644
--- a/backend/infrahub/message_bus/operations/event/schema.py
+++ b/backend/infrahub/message_bus/operations/event/schema.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.log import get_logger
from infrahub.message_bus import messages
from infrahub.services import InfrahubServices
@@ -5,6 +7,7 @@
log = get_logger()
+@flow(name="event-schema-update")
async def update(message: messages.EventSchemaUpdate, service: InfrahubServices) -> None:
log.info("run_message", branch=message.branch)
diff --git a/backend/infrahub/message_bus/operations/event/worker.py b/backend/infrahub/message_bus/operations/event/worker.py
index a47a22b1cd..c2f163882c 100644
--- a/backend/infrahub/message_bus/operations/event/worker.py
+++ b/backend/infrahub/message_bus/operations/event/worker.py
@@ -1,7 +1,10 @@
+from prefect import flow
+
from infrahub.message_bus import messages
from infrahub.services import InfrahubServices
+@flow(name="event-worker-newprimary-api")
async def new_primary_api(message: messages.EventWorkerNewPrimaryAPI, service: InfrahubServices) -> None:
service.log.info("api_worker promoted to primary", worker_id=message.worker_id)
diff --git a/backend/infrahub/message_bus/operations/finalize/validator.py b/backend/infrahub/message_bus/operations/finalize/validator.py
index 50a206fed1..5fe25f3d00 100644
--- a/backend/infrahub/message_bus/operations/finalize/validator.py
+++ b/backend/infrahub/message_bus/operations/finalize/validator.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub import config
from infrahub.core.timestamp import Timestamp
from infrahub.log import get_logger
@@ -8,6 +10,7 @@
log = get_logger()
+@flow(name="validator-finalize-execution")
async def execution(message: messages.FinalizeValidatorExecution, service: InfrahubServices) -> None:
"""Monitors the status of checks associated with a validator and finalizes the conclusion of the validator
diff --git a/backend/infrahub/message_bus/operations/git/branch.py b/backend/infrahub/message_bus/operations/git/branch.py
index 2c2fc76afa..931241096d 100644
--- a/backend/infrahub/message_bus/operations/git/branch.py
+++ b/backend/infrahub/message_bus/operations/git/branch.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub import lock
from infrahub.git.repository import InfrahubRepository
from infrahub.log import get_logger
@@ -7,6 +9,7 @@
log = get_logger()
+@flow(name="git-repository-branch-create")
async def create(message: messages.GitBranchCreate, service: InfrahubServices) -> None:
log.info("creating branch in repository", branch=message.branch, repository=message.repository_name)
repo = await InfrahubRepository.init(id=message.repository_id, name=message.repository_name, client=service.client)
diff --git a/backend/infrahub/message_bus/operations/git/diff.py b/backend/infrahub/message_bus/operations/git/diff.py
index 2b7d4678bb..8fada660ae 100644
--- a/backend/infrahub/message_bus/operations/git/diff.py
+++ b/backend/infrahub/message_bus/operations/git/diff.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.git.repository import get_initialized_repo
from infrahub.log import get_logger
from infrahub.message_bus import messages
@@ -7,6 +9,7 @@
log = get_logger()
+@flow(name="git-repository-diff-files-names-only")
async def names_only(message: messages.GitDiffNamesOnly, service: InfrahubServices) -> None:
log.info(
"Collecting modifications between commits",
diff --git a/backend/infrahub/message_bus/operations/git/file.py b/backend/infrahub/message_bus/operations/git/file.py
index 9594aa3e1d..4176b1cb8e 100644
--- a/backend/infrahub/message_bus/operations/git/file.py
+++ b/backend/infrahub/message_bus/operations/git/file.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.git.repository import get_initialized_repo
from infrahub.log import get_logger
from infrahub.message_bus import messages
@@ -7,6 +9,7 @@
log = get_logger()
+@flow(name="git-repository-get-file")
async def get(message: messages.GitFileGet, service: InfrahubServices) -> None:
log.info("Collecting file from repository", repository=message.repository_name, file=message.file)
diff --git a/backend/infrahub/message_bus/operations/git/repository.py b/backend/infrahub/message_bus/operations/git/repository.py
index ed8b36c561..b888b1087a 100644
--- a/backend/infrahub/message_bus/operations/git/repository.py
+++ b/backend/infrahub/message_bus/operations/git/repository.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub import lock
from infrahub.core.constants import InfrahubKind, RepositoryInternalStatus
from infrahub.exceptions import RepositoryError
@@ -13,6 +15,7 @@
log = get_logger()
+@flow(name="git-repository-add-read-write")
async def add(message: messages.GitRepositoryAdd, service: InfrahubServices) -> None:
log.info(
"Cloning and importing repository",
@@ -43,6 +46,7 @@ async def add(message: messages.GitRepositoryAdd, service: InfrahubServices) ->
await repo.sync()
+@flow(name="git-repository-add-read-only")
async def add_read_only(message: messages.GitRepositoryAddReadOnly, service: InfrahubServices) -> None:
log.info(
"Cloning and importing read-only repository", repository=message.repository_name, location=message.location
@@ -67,6 +71,7 @@ async def add_read_only(message: messages.GitRepositoryAddReadOnly, service: Inf
await repo.sync_from_remote()
+@flow(name="git-repository-check-connectivity")
async def connectivity(message: messages.GitRepositoryConnectivity, service: InfrahubServices) -> None:
response_data = GitRepositoryConnectivityResponseData(message="Successfully accessed repository", success=True)
@@ -83,6 +88,7 @@ async def connectivity(message: messages.GitRepositoryConnectivity, service: Inf
await service.reply(message=response, initiator=message)
+@flow(name="git-repository-import-object")
async def import_objects(message: messages.GitRepositoryImportObjects, service: InfrahubServices) -> None:
async with service.git_report(
related_node=message.repository_id,
@@ -98,6 +104,7 @@ async def import_objects(message: messages.GitRepositoryImportObjects, service:
await repo.import_objects_from_files(infrahub_branch_name=message.infrahub_branch_name, commit=message.commit)
+@flow(name="git-repository-pull-read-only")
async def pull_read_only(message: messages.GitRepositoryPullReadOnly, service: InfrahubServices) -> None:
if not message.ref and not message.commit:
log.warning(
@@ -148,6 +155,7 @@ async def pull_read_only(message: messages.GitRepositoryPullReadOnly, service: I
await repo.sync_from_remote(commit=message.commit)
+@flow(name="git-repository-merge")
async def merge(message: messages.GitRepositoryMerge, service: InfrahubServices) -> None:
log.info(
"Merging repository branch",
diff --git a/backend/infrahub/message_bus/operations/refresh/webhook.py b/backend/infrahub/message_bus/operations/refresh/webhook.py
index 8d07a6e79d..abc8fe6f44 100644
--- a/backend/infrahub/message_bus/operations/refresh/webhook.py
+++ b/backend/infrahub/message_bus/operations/refresh/webhook.py
@@ -1,10 +1,12 @@
import ujson
+from prefect import flow
from infrahub.core.constants import InfrahubKind
from infrahub.message_bus import messages
from infrahub.services import InfrahubServices
+@flow(name="registry-webhook-config-refresh")
async def configuration(
message: messages.RefreshWebhookConfiguration, # pylint: disable=unused-argument
service: InfrahubServices,
diff --git a/backend/infrahub/message_bus/operations/requests/artifact.py b/backend/infrahub/message_bus/operations/requests/artifact.py
index 6764978b76..eb04019d0b 100644
--- a/backend/infrahub/message_bus/operations/requests/artifact.py
+++ b/backend/infrahub/message_bus/operations/requests/artifact.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.git.repository import get_initialized_repo
from infrahub.log import get_logger
from infrahub.message_bus import messages
@@ -7,7 +9,8 @@
log = get_logger()
-async def generate(message: messages.RequestArtifactGenerate, service: InfrahubServices):
+@flow(name="artifact-generate")
+async def generate(message: messages.RequestArtifactGenerate, service: InfrahubServices) -> None:
log.debug("Generating artifact", message=message)
repo = await get_initialized_repo(
diff --git a/backend/infrahub/message_bus/operations/requests/artifact_definition.py b/backend/infrahub/message_bus/operations/requests/artifact_definition.py
index 2020d6f9d1..33d1552855 100644
--- a/backend/infrahub/message_bus/operations/requests/artifact_definition.py
+++ b/backend/infrahub/message_bus/operations/requests/artifact_definition.py
@@ -1,6 +1,7 @@
from typing import Optional
from infrahub_sdk import UUIDT
+from prefect import flow
from infrahub.core.constants import InfrahubKind, ValidatorConclusion, ValidatorState
from infrahub.core.timestamp import Timestamp
@@ -12,6 +13,7 @@
log = get_logger()
+@flow(name="artifact-definition-check")
async def check(message: messages.RequestArtifactDefinitionCheck, service: InfrahubServices) -> None:
async with service.task_report(
title=f"Artifact Definition: {message.artifact_definition.definition_name}",
@@ -134,6 +136,7 @@ async def check(message: messages.RequestArtifactDefinitionCheck, service: Infra
await service.send(message=event)
+@flow(name="artifact-definition-generate")
async def generate(message: messages.RequestArtifactDefinitionGenerate, service: InfrahubServices) -> None:
log.info(
"Received request to generate artifacts for an artifact_definition",
diff --git a/backend/infrahub/message_bus/operations/requests/diff.py b/backend/infrahub/message_bus/operations/requests/diff.py
index 479af29511..f15f016eb2 100644
--- a/backend/infrahub/message_bus/operations/requests/diff.py
+++ b/backend/infrahub/message_bus/operations/requests/diff.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.core import registry
from infrahub.core.diff.coordinator import DiffCoordinator
from infrahub.dependencies.registry import get_component_registry
@@ -8,6 +10,7 @@
log = get_logger()
+@flow(name="diff-update")
async def update(message: messages.RequestDiffUpdate, service: InfrahubServices) -> None:
component_registry = get_component_registry()
base_branch = await registry.get_branch(db=service.database, branch=registry.default_branch)
@@ -24,6 +27,7 @@ async def update(message: messages.RequestDiffUpdate, service: InfrahubServices)
)
+@flow(name="diff-refresh")
async def refresh(message: messages.RequestDiffRefresh, service: InfrahubServices) -> None:
component_registry = get_component_registry()
base_branch = await registry.get_branch(db=service.database, branch=registry.default_branch)
diff --git a/backend/infrahub/message_bus/operations/requests/generator.py b/backend/infrahub/message_bus/operations/requests/generator.py
index 1b62104332..130412f3ce 100644
--- a/backend/infrahub/message_bus/operations/requests/generator.py
+++ b/backend/infrahub/message_bus/operations/requests/generator.py
@@ -4,15 +4,17 @@
from infrahub_sdk.exceptions import ModuleImportError
from infrahub_sdk.protocols import CoreGeneratorInstance
from infrahub_sdk.schema import InfrahubGeneratorDefinitionConfig
+from prefect import flow
from infrahub import lock
-from infrahub.core.constants import GeneratorInstanceStatus, InfrahubKind
+from infrahub.core.constants import GeneratorInstanceStatus
from infrahub.git.base import extract_repo_file_information
from infrahub.git.repository import get_initialized_repo
from infrahub.message_bus import messages
from infrahub.services import InfrahubServices
+@flow(name="generator-run")
async def run(message: messages.RequestGeneratorRun, service: InfrahubServices) -> None:
repository = await get_initialized_repo(
repository_id=message.repository_id,
@@ -65,8 +67,8 @@ async def run(message: messages.RequestGeneratorRun, service: InfrahubServices)
async def _define_instance(message: messages.RequestGeneratorRun, service: InfrahubServices) -> CoreGeneratorInstance:
if message.generator_instance:
- instance: CoreGeneratorInstance = await service.client.get(
- kind=InfrahubKind.GENERATORINSTANCE, id=message.generator_instance, branch=message.branch_name
+ instance = await service.client.get(
+ kind=CoreGeneratorInstance, id=message.generator_instance, branch=message.branch_name
)
instance.status.value = GeneratorInstanceStatus.PENDING.value
await instance.update(do_full_update=True)
@@ -75,8 +77,8 @@ async def _define_instance(message: messages.RequestGeneratorRun, service: Infra
async with lock.registry.get(
f"{message.target_id}-{message.generator_definition.definition_id}", namespace="generator"
):
- instances: list[CoreGeneratorInstance] = await service.client.filters(
- kind=InfrahubKind.GENERATORINSTANCE,
+ instances = await service.client.filters(
+ kind=CoreGeneratorInstance,
definition__ids=[message.generator_definition.definition_id],
object__ids=[message.target_id],
branch=message.branch_name,
@@ -87,7 +89,7 @@ async def _define_instance(message: messages.RequestGeneratorRun, service: Infra
await instance.update(do_full_update=True)
else:
instance = await service.client.create(
- kind=InfrahubKind.GENERATORINSTANCE,
+ kind=CoreGeneratorInstance,
branch=message.branch_name,
data={
"name": f"{message.generator_definition.definition_name}: {message.target_name}",
diff --git a/backend/infrahub/message_bus/operations/requests/generator_definition.py b/backend/infrahub/message_bus/operations/requests/generator_definition.py
index 92c03e839e..7792bcaa48 100644
--- a/backend/infrahub/message_bus/operations/requests/generator_definition.py
+++ b/backend/infrahub/message_bus/operations/requests/generator_definition.py
@@ -1,6 +1,7 @@
from typing import Optional
from infrahub_sdk import UUIDT
+from prefect import flow
from infrahub.core.constants import InfrahubKind, ValidatorConclusion, ValidatorState
from infrahub.core.timestamp import Timestamp
@@ -9,6 +10,7 @@
from infrahub.services import InfrahubServices
+@flow(name="generator-definition-check")
async def check(message: messages.RequestGeneratorDefinitionCheck, service: InfrahubServices) -> None:
async with service.task_report(
title=f"Generator Definition: {message.generator_definition.definition_name}",
@@ -127,6 +129,7 @@ async def check(message: messages.RequestGeneratorDefinitionCheck, service: Infr
await service.send(message=event)
+@flow(name="generator-definition-run")
async def run(message: messages.RequestGeneratorDefinitionRun, service: InfrahubServices) -> None:
async with service.task_report(
title="Executing Generator",
diff --git a/backend/infrahub/message_bus/operations/requests/git.py b/backend/infrahub/message_bus/operations/requests/git.py
index f388bf09d5..d1d20bf86b 100644
--- a/backend/infrahub/message_bus/operations/requests/git.py
+++ b/backend/infrahub/message_bus/operations/requests/git.py
@@ -1,5 +1,7 @@
from typing import List
+from prefect import flow
+
from infrahub.core.constants import InfrahubKind
from infrahub.git.actions import sync_remote_repositories
from infrahub.log import get_logger
@@ -9,6 +11,7 @@
log = get_logger()
+@flow(name="git-repository-branch-create")
async def create_branch(message: messages.RequestGitCreateBranch, service: InfrahubServices) -> None:
"""Request to the creation of git branches in available repositories."""
log.info("Querying repositories for branch creation")
@@ -28,6 +31,7 @@ async def create_branch(message: messages.RequestGitCreateBranch, service: Infra
await service.send(message=event)
+@flow(name="git-repository-sync")
async def sync(
message: messages.RequestGitSync, # pylint: disable=unused-argument
service: InfrahubServices,
diff --git a/backend/infrahub/message_bus/operations/requests/graphql_query_group.py b/backend/infrahub/message_bus/operations/requests/graphql_query_group.py
index 3417c549c0..da8a906572 100644
--- a/backend/infrahub/message_bus/operations/requests/graphql_query_group.py
+++ b/backend/infrahub/message_bus/operations/requests/graphql_query_group.py
@@ -2,6 +2,7 @@
from infrahub_sdk import InfrahubClient, InfrahubNode
from infrahub_sdk.utils import dict_hash
+from prefect import flow
from infrahub.core.constants import InfrahubKind
from infrahub.log import get_logger
@@ -11,7 +12,9 @@
log = get_logger()
-async def group_add_subscriber(client: InfrahubClient, group: InfrahubNode, subscribers: List[str], branch: str):
+async def group_add_subscriber(
+ client: InfrahubClient, group: InfrahubNode, subscribers: List[str], branch: str
+) -> dict:
subscribers_str = ["{ id: " + f'"{subscriber}"' + " }" for subscriber in subscribers]
query = """
mutation {
@@ -33,6 +36,7 @@ async def group_add_subscriber(client: InfrahubClient, group: InfrahubNode, subs
return await client.execute_graphql(query=query, branch_name=branch, tracker="mutation-relationshipadd")
+@flow(name="graphql-query-update")
async def update(message: messages.RequestGraphQLQueryGroupUpdate, service: InfrahubServices) -> None:
"""Create or Update a GraphQLQueryGroup."""
diff --git a/backend/infrahub/message_bus/operations/requests/proposed_change.py b/backend/infrahub/message_bus/operations/requests/proposed_change.py
index 22158775a2..ddff626ced 100644
--- a/backend/infrahub/message_bus/operations/requests/proposed_change.py
+++ b/backend/infrahub/message_bus/operations/requests/proposed_change.py
@@ -8,6 +8,8 @@
from typing import TYPE_CHECKING, Union
import pytest
+from infrahub_sdk.protocols import CoreGeneratorDefinition, CoreProposedChange
+from prefect import flow
from pydantic import BaseModel
from infrahub import config, lock
@@ -30,14 +32,13 @@
ProposedChangeSubscriber,
)
from infrahub.pytest_plugin import InfrahubBackendPlugin
+from infrahub.services import InfrahubServices # noqa: TCH001
if TYPE_CHECKING:
from infrahub_sdk.node import InfrahubNode
- from infrahub_sdk.protocols import CoreGeneratorDefinition, CoreProposedChange
from infrahub.core.models import SchemaUpdateConstraintInfo
- from infrahub.core.schema_manager import SchemaBranch
- from infrahub.services import InfrahubServices
+ from infrahub.core.schema.schema_branch import SchemaBranch
log = get_logger()
@@ -69,6 +70,7 @@ def log_line(self) -> str:
return "Doesn't require changes due to no relevant modified kinds or file changes in Git"
+@flow(name="proposed-changed-cancel")
async def cancel(message: messages.RequestProposedChangeCancel, service: InfrahubServices) -> None:
"""Cancel a proposed change."""
async with service.task_report(
@@ -76,13 +78,12 @@ async def cancel(message: messages.RequestProposedChangeCancel, service: Infrahu
title="Canceling proposed change",
) as task_report:
await task_report.info("Canceling proposed change as the source branch was deleted", id=message.proposed_change)
- proposed_change: CoreProposedChange = await service.client.get(
- kind=InfrahubKind.PROPOSEDCHANGE, id=message.proposed_change
- )
+ proposed_change = await service.client.get(kind=CoreProposedChange, id=message.proposed_change)
proposed_change.state.value = ProposedChangeState.CANCELED.value
await proposed_change.save()
+@flow(name="proposed-changed-data-integrity")
async def data_integrity(message: messages.RequestProposedChangeDataIntegrity, service: InfrahubServices) -> None:
"""Triggers a data integrity validation check on the provided proposed change to start."""
async with service.task_report(
@@ -99,6 +100,7 @@ async def data_integrity(message: messages.RequestProposedChangeDataIntegrity, s
await diff_coordinator.update_branch_diff(base_branch=destination_branch, diff_branch=source_branch)
+@flow(name="proposed-changed-pipeline")
async def pipeline(message: messages.RequestProposedChangePipeline, service: InfrahubServices) -> None:
async with service.task_report(
related_node=message.proposed_change,
@@ -221,6 +223,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
await service.send(message=event)
+@flow(name="proposed-changed-schema-integrity")
async def schema_integrity(
message: messages.RequestProposedChangeSchemaIntegrity,
service: InfrahubServices, # pylint: disable=unused-argument
@@ -288,6 +291,7 @@ async def schema_integrity(
)
+@flow(name="proposed-changed-repository-check")
async def repository_checks(message: messages.RequestProposedChangeRepositoryChecks, service: InfrahubServices) -> None:
async with service.task_report(
related_node=message.proposed_change,
@@ -328,6 +332,7 @@ async def repository_checks(message: messages.RequestProposedChangeRepositoryChe
await service.send(message=event)
+@flow(name="proposed-changed-refresh-artifact")
async def refresh_artifacts(message: messages.RequestProposedChangeRefreshArtifacts, service: InfrahubServices) -> None:
async with service.task_report(
related_node=message.proposed_change,
@@ -391,6 +396,7 @@ async def refresh_artifacts(message: messages.RequestProposedChangeRefreshArtifa
await service.send(message=msg)
+@flow(name="proposed-changed-run-generator")
async def run_generators(message: messages.RequestProposedChangeRunGenerators, service: InfrahubServices) -> None:
async with service.task_report(
related_node=message.proposed_change,
@@ -557,6 +563,7 @@ async def run_generators(message: messages.RequestProposedChangeRunGenerators, s
"""
+@flow(name="proposed-changed-run-tests")
async def run_tests(message: messages.RequestProposedChangeRunTests, service: InfrahubServices) -> None:
async with service.task_report(
related_node=message.proposed_change,
diff --git a/backend/infrahub/message_bus/operations/requests/repository.py b/backend/infrahub/message_bus/operations/requests/repository.py
index 872196a2f8..1646edf0e0 100644
--- a/backend/infrahub/message_bus/operations/requests/repository.py
+++ b/backend/infrahub/message_bus/operations/requests/repository.py
@@ -1,6 +1,7 @@
from typing import List
from infrahub_sdk import UUIDT
+from prefect import flow
from infrahub.core.constants import InfrahubKind
from infrahub.core.timestamp import Timestamp
@@ -12,7 +13,8 @@
log = get_logger()
-async def checks(message: messages.RequestRepositoryChecks, service: InfrahubServices):
+@flow(name="repository-check")
+async def checks(message: messages.RequestRepositoryChecks, service: InfrahubServices) -> None:
"""Request to start validation checks on a specific repository."""
log.info("Running repository checks", repository_id=message.repository, proposed_change_id=message.proposed_change)
@@ -94,7 +96,8 @@ async def checks(message: messages.RequestRepositoryChecks, service: InfrahubSer
await service.send(message=event)
-async def user_checks(message: messages.RequestRepositoryUserChecks, service: InfrahubServices):
+@flow(name="repository-users-check")
+async def user_checks(message: messages.RequestRepositoryUserChecks, service: InfrahubServices) -> None:
"""Request to start validation checks on a specific repository for User-defined checks."""
async with service.task_report(
related_node=message.proposed_change,
diff --git a/backend/infrahub/message_bus/operations/schema/migration.py b/backend/infrahub/message_bus/operations/schema/migration.py
index 9de2f67424..9adf96b324 100644
--- a/backend/infrahub/message_bus/operations/schema/migration.py
+++ b/backend/infrahub/message_bus/operations/schema/migration.py
@@ -1,15 +1,21 @@
+from prefect import flow, task
+from prefect.logging import get_run_logger
+from prefect.runtime import task_run
+
from infrahub.core.migrations import MIGRATION_MAP
from infrahub.log import get_logger
from infrahub.message_bus.messages.schema_migration_path import (
SchemaMigrationPath,
+ SchemaMigrationPathData,
SchemaMigrationPathResponse,
SchemaMigrationPathResponseData,
)
-from infrahub.services import InfrahubServices
+from infrahub.services import InfrahubServices, services
log = get_logger()
+@flow(name="schema-migration-path")
async def path(message: SchemaMigrationPath, service: InfrahubServices) -> None:
async with service.database.start_session() as db:
node_kind = None
@@ -52,3 +58,60 @@ async def path(message: SchemaMigrationPath, service: InfrahubServices) -> None:
)
)
await service.reply(message=response, initiator=message)
+
+
+def generate_task_name() -> str:
+ task_name = task_run.task_name
+ message: SchemaMigrationPathData = task_run.parameters["message"]
+ return f"{task_name}-{message.branch.name}-{message.migration_name}"
+
+
+@task(
+ task_run_name=generate_task_name,
+ description="Apply a given migration to the database",
+ retries=3,
+)
+async def schema_path_migrate(message: SchemaMigrationPathData) -> SchemaMigrationPathResponseData:
+ service = services.service
+ logger = get_run_logger()
+
+ async with service.database.start_session() as db:
+ node_kind = None
+ if message.new_node_schema:
+ node_kind = message.new_node_schema.kind
+ elif message.previous_node_schema:
+ node_kind = message.previous_node_schema.kind
+
+ service.log.info(
+ "schema.migration.path - received",
+ migration=message.migration_name,
+ node_kind=node_kind,
+ path=message.schema_path.get_path(),
+ )
+ migration_class = MIGRATION_MAP.get(message.migration_name)
+ if not migration_class:
+ raise ValueError(f"Unable to find the migration class for {message.migration_name}")
+
+ migration = migration_class(
+ new_node_schema=message.new_node_schema,
+ previous_node_schema=message.previous_node_schema,
+ schema_path=message.schema_path,
+ )
+ execution_result = await migration.execute(db=db, branch=message.branch)
+
+ logger.info(f"Migration completed for {message.migration_name}")
+
+ service.log.info(
+ "schema.migration.path - completed",
+ migration=message.migration_name,
+ node_kind=node_kind,
+ path=message.schema_path.get_path(),
+ result=execution_result,
+ )
+
+ return SchemaMigrationPathResponseData(
+ migration_name=message.migration_name,
+ schema_path=message.schema_path,
+ errors=execution_result.errors,
+ nbr_migrations_executed=execution_result.nbr_migrations_executed,
+ )
diff --git a/backend/infrahub/message_bus/operations/schema/validator.py b/backend/infrahub/message_bus/operations/schema/validator.py
index 3e2ed75b2d..02ee3983be 100644
--- a/backend/infrahub/message_bus/operations/schema/validator.py
+++ b/backend/infrahub/message_bus/operations/schema/validator.py
@@ -1,17 +1,22 @@
+from prefect import flow, task
+from prefect.runtime import task_run
+
from infrahub.core.validators.aggregated_checker import AggregatedConstraintChecker
from infrahub.core.validators.model import SchemaConstraintValidatorRequest
from infrahub.dependencies.registry import get_component_registry
from infrahub.log import get_logger
from infrahub.message_bus.messages.schema_validator_path import (
SchemaValidatorPath,
+ SchemaValidatorPathData,
SchemaValidatorPathResponse,
SchemaValidatorPathResponseData,
)
-from infrahub.services import InfrahubServices
+from infrahub.services import InfrahubServices, services
log = get_logger()
+@flow(name="schema-validator-path")
async def path(message: SchemaValidatorPath, service: InfrahubServices) -> None:
async with service.database.start_session() as db:
log.info(
@@ -41,3 +46,43 @@ async def path(message: SchemaValidatorPath, service: InfrahubServices) -> None:
)
)
await service.reply(message=response, initiator=message)
+
+
+def generate_task_name() -> str:
+ task_name = task_run.task_name
+ message: SchemaValidatorPathData = task_run.parameters["message"]
+ return f"{task_name}-{message.branch.name}-{message.constraint_name}"
+
+
+@task(
+ task_run_name=generate_task_name,
+ description="Validate if a given migration is compatible with the existing data",
+ retries=3,
+)
+async def schema_path_validate(message: SchemaValidatorPathData) -> SchemaValidatorPathResponseData:
+ service = services.service
+
+ async with service.database.start_session() as db:
+ log.info(
+ "schema.validator.path",
+ constraint=message.constraint_name,
+ node_kind=message.node_schema.kind,
+ path=message.schema_path.get_path(),
+ )
+
+ constraint_request = SchemaConstraintValidatorRequest(
+ branch=message.branch,
+ constraint_name=message.constraint_name,
+ node_schema=message.node_schema,
+ schema_path=message.schema_path,
+ )
+
+ component_registry = get_component_registry()
+ aggregated_constraint_checker = await component_registry.get_component(
+ AggregatedConstraintChecker, db=db, branch=message.branch
+ )
+ violations = await aggregated_constraint_checker.run_constraints(constraint_request)
+
+ return SchemaValidatorPathResponseData(
+ violations=violations, constraint_name=message.constraint_name, schema_path=message.schema_path
+ )
diff --git a/backend/infrahub/message_bus/operations/send/echo.py b/backend/infrahub/message_bus/operations/send/echo.py
index f6c3629fc6..e0dce262c3 100644
--- a/backend/infrahub/message_bus/operations/send/echo.py
+++ b/backend/infrahub/message_bus/operations/send/echo.py
@@ -1,8 +1,11 @@
+from prefect import flow
+
from infrahub.message_bus import messages
from infrahub.message_bus.messages.send_echo_request import SendEchoRequestResponse, SendEchoRequestResponseData
from infrahub.services import InfrahubServices
+@flow(name="echo-request")
async def request(message: messages.SendEchoRequest, service: InfrahubServices) -> None:
service.log.info(f"Received message: {message.message}")
if message.reply_requested:
diff --git a/backend/infrahub/message_bus/operations/send/telemetry.py b/backend/infrahub/message_bus/operations/send/telemetry.py
index ad4ccc9997..4e6a36fa48 100644
--- a/backend/infrahub/message_bus/operations/send/telemetry.py
+++ b/backend/infrahub/message_bus/operations/send/telemetry.py
@@ -2,23 +2,27 @@
import json
import platform
import time
+from typing import Any
-import httpx
+from prefect import flow, task
+from prefect.logging import get_run_logger
from infrahub import __version__, config
from infrahub.core import registry, utils
from infrahub.core.branch import Branch
from infrahub.core.constants import InfrahubKind
from infrahub.core.graph.schema import GRAPH_SCHEMA
+from infrahub.exceptions import HTTPServerError
from infrahub.message_bus import messages
-from infrahub.services import InfrahubServices
+from infrahub.services import InfrahubServices, services
TELEMETRY_KIND: str = "community"
TELEMETRY_VERSION: str = "20240524"
+@task
async def gather_database_information(service: InfrahubServices, branch: Branch) -> dict: # pylint: disable=unused-argument
- data = {
+ data: dict[str, Any] = {
"database_type": service.database.db_type.value,
"relationship_count": {"total": await utils.count_relationships(db=service.database)},
"node_count": {"total": await utils.count_nodes(db=service.database)},
@@ -33,8 +37,9 @@ async def gather_database_information(service: InfrahubServices, branch: Branch)
return data
+@task
async def gather_schema_information(service: InfrahubServices, branch: Branch) -> dict: # pylint: disable=unused-argument
- data = {}
+ data: dict[str, Any] = {}
main_schema = registry.schema.get_schema_branch(name=branch.name)
data["node_count"] = len(main_schema.node_names)
data["generic_count"] = len(main_schema.generic_names)
@@ -43,6 +48,7 @@ async def gather_schema_information(service: InfrahubServices, branch: Branch) -
return data
+@task
async def gather_feature_information(service: InfrahubServices, branch: Branch) -> dict: # pylint: disable=unused-argument
data = {}
features_to_count = [
@@ -60,13 +66,14 @@ async def gather_feature_information(service: InfrahubServices, branch: Branch)
return data
+@task
async def gather_anonymous_telemetry_data(service: InfrahubServices) -> dict:
start_time = time.time()
default_branch = registry.get_branch_from_registry()
workers = await service.component.list_workers(branch=default_branch.name, schema_hash=False)
- data = {
+ data: dict[str, Any] = {
"deployment_id": registry.id,
"execution_time": None,
"infrahub_version": __version__,
@@ -89,6 +96,7 @@ async def gather_anonymous_telemetry_data(service: InfrahubServices) -> dict:
return data
+@flow(name="telemetry-push-legacy")
async def push(
message: messages.SendTelemetryPush, # pylint: disable=unused-argument
service: InfrahubServices,
@@ -98,6 +106,37 @@ async def push(
data = await gather_anonymous_telemetry_data(service=service)
service.log.debug(f"Anonymous usage telemetry gathered in {data['execution_time']} seconds.")
+ payload = {
+ "kind": TELEMETRY_KIND,
+ "payload_format": TELEMETRY_VERSION,
+ "data": data,
+ "checksum": hashlib.sha256(json.dumps(data).encode()).hexdigest(),
+ }
+ try:
+ response = await service.http.post(url=config.SETTINGS.main.telemetry_endpoint, json=payload)
+ except HTTPServerError as exc:
+ service.log.debug(f"HTTP exception while pushing anonymous telemetry: {exc}")
+ if not response.is_success:
+ service.log.debug("HTTP exception while pushing anonymous telemetry", status_code=response.status_code)
+
+
+@task(retries=5)
+async def post_telemetry_data(service: InfrahubServices, url: str, payload: dict[str, Any]) -> None:
+ """Send the telemetry data to the specified URL, using HTTP POST."""
+ response = await service.http.post(url=url, json=payload)
+ response.raise_for_status()
+
+
+@flow
+async def send_telemetry_push() -> None:
+ service = services.service
+
+ log = get_run_logger()
+ log.info(f"Pushing anonymous telemetry data to {config.SETTINGS.main.telemetry_endpoint}...")
+
+ data = await gather_anonymous_telemetry_data(service=service)
+ log.info(f"Anonymous usage telemetry gathered in {data['execution_time']} seconds. | {data}")
+
payload = {
"kind": TELEMETRY_KIND,
"payload_format": TELEMETRY_VERSION,
@@ -105,9 +144,4 @@ async def push(
"checksum": hashlib.sha256(json.dumps(data).encode()).hexdigest(),
}
- async with httpx.AsyncClient(timeout=5.0) as client:
- try:
- response = await client.post(config.SETTINGS.main.telemetry_endpoint, json=payload)
- response.raise_for_status()
- except httpx.HTTPError as exc:
- service.log.debug(f"HTTP exception while pushing anonymous telemetry: {exc}")
+ await post_telemetry_data(service=service, url=config.SETTINGS.main.telemetry_endpoint, payload=payload)
diff --git a/backend/infrahub/message_bus/operations/send/webhook.py b/backend/infrahub/message_bus/operations/send/webhook.py
index 5b1df4cc76..4110d78fac 100644
--- a/backend/infrahub/message_bus/operations/send/webhook.py
+++ b/backend/infrahub/message_bus/operations/send/webhook.py
@@ -1,11 +1,17 @@
+from typing import Any
+
import ujson
+from prefect import flow
+from prefect.logging import get_run_logger
from infrahub.exceptions import NodeNotFoundError
from infrahub.message_bus import messages
-from infrahub.services import InfrahubServices
+from infrahub.message_bus.messages.send_webhook_event import SendWebhookData
+from infrahub.services import InfrahubServices, services
from infrahub.webhook import CustomWebhook, StandardWebhook, TransformWebhook, Webhook
+@flow(name="event-send-webhook")
async def event(message: messages.SendWebhookEvent, service: InfrahubServices) -> None:
async with service.task_report(
related_node=message.webhook_id,
@@ -19,7 +25,7 @@ async def event(message: messages.SendWebhookEvent, service: InfrahubServices) -
)
webhook_data = ujson.loads(webhook_definition)
- payload = {"event_type": message.event_type, "data": message.event_data, "service": service}
+ payload: dict[str, Any] = {"event_type": message.event_type, "data": message.event_data, "service": service}
webhook_map: dict[str, type[Webhook]] = {
"standard": StandardWebhook,
"custom": CustomWebhook,
@@ -33,3 +39,30 @@ async def event(message: messages.SendWebhookEvent, service: InfrahubServices) -
title=webhook.webhook_type,
logs={"message": "Successfully sent webhook", "severity": "INFO"},
)
+
+
+@flow
+async def send_webhook(message: SendWebhookData) -> None:
+ service = services.service
+ log = get_run_logger()
+
+ webhook_definition = await service.cache.get(key=f"webhook:active:{message.webhook_id}")
+ if not webhook_definition:
+ log.warning("Webhook not found")
+ raise NodeNotFoundError(
+ node_type="Webhook", identifier=message.webhook_id, message="The requested Webhook was not found"
+ )
+
+ webhook_data = ujson.loads(webhook_definition)
+ payload: dict[str, Any] = {"event_type": message.event_type, "data": message.event_data, "service": service}
+ webhook_map: dict[str, type[Webhook]] = {
+ "standard": StandardWebhook,
+ "custom": CustomWebhook,
+ "transform": TransformWebhook,
+ }
+ webhook_class = webhook_map[webhook_data["webhook_type"]]
+ payload.update(webhook_data["webhook_configuration"])
+ webhook = webhook_class(**payload)
+ await webhook.send()
+
+ log.info("Successfully sent webhook")
diff --git a/backend/infrahub/message_bus/operations/transform/jinja.py b/backend/infrahub/message_bus/operations/transform/jinja.py
index a861ea5946..6661474484 100644
--- a/backend/infrahub/message_bus/operations/transform/jinja.py
+++ b/backend/infrahub/message_bus/operations/transform/jinja.py
@@ -1,15 +1,19 @@
+from prefect import flow
+
from infrahub.git.repository import get_initialized_repo
from infrahub.log import get_logger
from infrahub.message_bus.messages.transform_jinja_template import (
TransformJinjaTemplate,
+ TransformJinjaTemplateData,
TransformJinjaTemplateResponse,
TransformJinjaTemplateResponseData,
)
-from infrahub.services import InfrahubServices
+from infrahub.services import InfrahubServices, services
log = get_logger()
+@flow(name="transform-render-jinja2-legacy")
async def template(message: TransformJinjaTemplate, service: InfrahubServices) -> None:
log.info(f"Received request to render a Jinja template on branch={message.branch}")
@@ -28,3 +32,20 @@ async def template(message: TransformJinjaTemplate, service: InfrahubServices) -
data=TransformJinjaTemplateResponseData(rendered_template=rendered_template),
)
await service.reply(message=response, initiator=message)
+
+
+@flow(persist_result=True)
+async def transform_render_jinja2_template(message: TransformJinjaTemplateData) -> str:
+ service = services.service
+ repo = await get_initialized_repo(
+ repository_id=message.repository_id,
+ name=message.repository_name,
+ service=service,
+ repository_kind=message.repository_kind,
+ )
+
+ rendered_template = await repo.render_jinja2_template(
+ commit=message.commit, location=message.template_location, data={"data": message.data}
+ )
+
+ return rendered_template
diff --git a/backend/infrahub/message_bus/operations/transform/python.py b/backend/infrahub/message_bus/operations/transform/python.py
index a93a33c1f9..8023267cc9 100644
--- a/backend/infrahub/message_bus/operations/transform/python.py
+++ b/backend/infrahub/message_bus/operations/transform/python.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.git.repository import get_initialized_repo
from infrahub.log import get_logger
from infrahub.message_bus import messages
@@ -10,6 +12,7 @@
log = get_logger()
+@flow(name="transform-render-python-legacy")
async def data(message: messages.TransformPythonData, service: InfrahubServices) -> None:
log.info(
"Received request to transform Python data",
diff --git a/backend/infrahub/message_bus/operations/trigger/artifact_definition.py b/backend/infrahub/message_bus/operations/trigger/artifact_definition.py
index 27013e25ff..1b614f287c 100644
--- a/backend/infrahub/message_bus/operations/trigger/artifact_definition.py
+++ b/backend/infrahub/message_bus/operations/trigger/artifact_definition.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.core.constants import InfrahubKind
from infrahub.log import get_logger
from infrahub.message_bus import messages
@@ -6,6 +8,7 @@
log = get_logger()
+@flow(name="artifact-definition-generate")
async def generate(message: messages.TriggerArtifactDefinitionGenerate, service: InfrahubServices) -> None:
artifact_definitions = await service.client.all(
kind=InfrahubKind.ARTIFACTDEFINITION, branch=message.branch, include=["id"]
diff --git a/backend/infrahub/message_bus/operations/trigger/generator_definition.py b/backend/infrahub/message_bus/operations/trigger/generator_definition.py
index c9825add03..b9044806ab 100644
--- a/backend/infrahub/message_bus/operations/trigger/generator_definition.py
+++ b/backend/infrahub/message_bus/operations/trigger/generator_definition.py
@@ -1,9 +1,12 @@
+from prefect import flow
+
from infrahub.core.constants import InfrahubKind
from infrahub.message_bus import messages
from infrahub.message_bus.types import ProposedChangeGeneratorDefinition
from infrahub.services import InfrahubServices
+@flow(name="generator-definition-run")
async def run(message: messages.TriggerGeneratorDefinitionRun, service: InfrahubServices) -> None:
generators = await service.client.filters(
kind=InfrahubKind.GENERATORDEFINITION, prefetch_relationships=True, populate_store=True, branch=message.branch
diff --git a/backend/infrahub/message_bus/operations/trigger/ipam.py b/backend/infrahub/message_bus/operations/trigger/ipam.py
index 49dba8bf78..79b61b34fc 100644
--- a/backend/infrahub/message_bus/operations/trigger/ipam.py
+++ b/backend/infrahub/message_bus/operations/trigger/ipam.py
@@ -1,4 +1,7 @@
import ipaddress
+from typing import TYPE_CHECKING
+
+from prefect import flow
from infrahub.core import registry
from infrahub.core.ipam.reconciler import IpamReconciler
@@ -6,16 +9,20 @@
from infrahub.message_bus import messages
from infrahub.services import InfrahubServices
+if TYPE_CHECKING:
+ from infrahub.core.ipam.constants import AllIPTypes
+
log = get_logger()
+@flow(name="ipam-reconciliation")
async def reconciliation(message: messages.TriggerIpamReconciliation, service: InfrahubServices) -> None:
branch = await registry.get_branch(db=service.database, branch=message.branch)
ipam_reconciler = IpamReconciler(db=service.database, branch=branch)
for ipam_node_details in message.ipam_node_details:
if ipam_node_details.is_address:
- ip_value = ipaddress.ip_interface(ipam_node_details.ip_value)
+ ip_value: AllIPTypes = ipaddress.ip_interface(ipam_node_details.ip_value)
else:
ip_value = ipaddress.ip_network(ipam_node_details.ip_value)
await ipam_reconciler.reconcile(
diff --git a/backend/infrahub/message_bus/operations/trigger/proposed_change.py b/backend/infrahub/message_bus/operations/trigger/proposed_change.py
index 2519425b75..1f2f2d2f68 100644
--- a/backend/infrahub/message_bus/operations/trigger/proposed_change.py
+++ b/backend/infrahub/message_bus/operations/trigger/proposed_change.py
@@ -1,3 +1,5 @@
+from prefect import flow
+
from infrahub.core.constants import InfrahubKind, ProposedChangeState
from infrahub.log import get_logger
from infrahub.message_bus import messages
@@ -6,6 +8,7 @@
log = get_logger()
+@flow(name="proposed-change-cancel")
async def cancel(message: messages.TriggerProposedChangeCancel, service: InfrahubServices) -> None:
proposed_changed_opened = await service.client.filters(
kind=InfrahubKind.PROPOSEDCHANGE, include=["id", "source_branch"], state__value=ProposedChangeState.OPEN.value
diff --git a/backend/infrahub/message_bus/operations/trigger/webhook.py b/backend/infrahub/message_bus/operations/trigger/webhook.py
index 4f6034721f..200459a8c0 100644
--- a/backend/infrahub/message_bus/operations/trigger/webhook.py
+++ b/backend/infrahub/message_bus/operations/trigger/webhook.py
@@ -1,9 +1,12 @@
from typing import List
+from prefect import flow
+
from infrahub.message_bus import InfrahubMessage, messages
from infrahub.services import InfrahubServices
+@flow(name="webhook-trigger-actions")
async def actions(message: messages.TriggerWebhookActions, service: InfrahubServices) -> None:
webhooks = await service.cache.list_keys(filter_pattern="webhook:active:*")
events: List[InfrahubMessage] = []
diff --git a/backend/infrahub/middleware.py b/backend/infrahub/middleware.py
index 4f9cd37d0c..99060de738 100644
--- a/backend/infrahub/middleware.py
+++ b/backend/infrahub/middleware.py
@@ -7,7 +7,7 @@
class InfrahubCORSMiddleware(CORSMiddleware):
- def __init__(self, app: ASGIApp, *args: Any, **kwargs: Any):
+ def __init__(self, app: ASGIApp, *args: Any, **kwargs: Any) -> None:
config.SETTINGS.initialize_and_exit()
kwargs["allow_origins"] = config.SETTINGS.api.cors_allow_origins
kwargs["allow_credentials"] = config.SETTINGS.api.cors_allow_credentials
diff --git a/backend/infrahub/models.py b/backend/infrahub/models.py
index 4f9f60c5e2..d2c2641475 100644
--- a/backend/infrahub/models.py
+++ b/backend/infrahub/models.py
@@ -13,6 +13,10 @@ class UserToken(BaseModel):
refresh_token: str = Field(..., description="JWT refresh_token")
+class UserTokenWithUrl(UserToken):
+ final_url: str = Field(..., description="The final url after logged in")
+
+
class AccessTokenResponse(BaseModel):
access_token: str = Field(..., description="JWT access_token")
diff --git a/backend/infrahub/permissions/__init__.py b/backend/infrahub/permissions/__init__.py
new file mode 100644
index 0000000000..e5ed3928ef
--- /dev/null
+++ b/backend/infrahub/permissions/__init__.py
@@ -0,0 +1,4 @@
+from .backend import PermissionBackend
+from .local_backend import LocalPermissionBackend
+
+__all__ = ["LocalPermissionBackend", "PermissionBackend"]
diff --git a/backend/infrahub/permissions/backend.py b/backend/infrahub/permissions/backend.py
new file mode 100644
index 0000000000..ed404f6bc8
--- /dev/null
+++ b/backend/infrahub/permissions/backend.py
@@ -0,0 +1,17 @@
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.database import InfrahubDatabase
+ from infrahub.permissions.constants import AssignedPermissions
+
+
+class PermissionBackend(ABC):
+ @abstractmethod
+ async def load_permissions(self, db: InfrahubDatabase, account_id: str, branch: Branch) -> AssignedPermissions: ...
+
+ @abstractmethod
+ async def has_permission(self, db: InfrahubDatabase, account_id: str, permission: str, branch: Branch) -> bool: ...
diff --git a/backend/infrahub/permissions/constants.py b/backend/infrahub/permissions/constants.py
new file mode 100644
index 0000000000..3dad122d62
--- /dev/null
+++ b/backend/infrahub/permissions/constants.py
@@ -0,0 +1,11 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, TypedDict
+
+if TYPE_CHECKING:
+ from infrahub.core.account import GlobalPermission, ObjectPermission
+
+
+class AssignedPermissions(TypedDict):
+ global_permissions: list[GlobalPermission]
+ object_permissions: list[ObjectPermission]
diff --git a/backend/infrahub/permissions/local_backend.py b/backend/infrahub/permissions/local_backend.py
new file mode 100644
index 0000000000..76df5b334f
--- /dev/null
+++ b/backend/infrahub/permissions/local_backend.py
@@ -0,0 +1,92 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from infrahub.core.account import GlobalPermission, ObjectPermission, fetch_permissions
+from infrahub.core.constants import GlobalPermissions, PermissionDecision
+
+from .backend import PermissionBackend
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.database import InfrahubDatabase
+ from infrahub.permissions.constants import AssignedPermissions
+
+
+class LocalPermissionBackend(PermissionBackend):
+ wildcard_values = ["*"]
+ wildcard_actions = ["any"]
+
+ def compute_specificity(self, permission: ObjectPermission) -> int:
+ specificity = 0
+ if permission.branch not in self.wildcard_values:
+ specificity += 1
+ if permission.namespace not in self.wildcard_values:
+ specificity += 1
+ if permission.name not in self.wildcard_values:
+ specificity += 1
+ if permission.action not in self.wildcard_actions:
+ specificity += 1
+ return specificity
+
+ def resolve_object_permission(self, permissions: list[ObjectPermission], permission_to_check: str) -> bool:
+ """Compute the permissions and check if the one provided is allowed."""
+ if not permission_to_check.startswith("object:"):
+ return False
+
+ most_specific_permission: str | None = None
+ highest_specificity: int = -1
+ _, branch, namespace, name, action, _ = permission_to_check.split(":")
+
+ for permission in permissions:
+ if (
+ permission.branch in [branch, *self.wildcard_values]
+ and permission.namespace in [namespace, *self.wildcard_values]
+ and permission.name in [name, *self.wildcard_values]
+ and permission.action in [action, *self.wildcard_actions]
+ ):
+ # Compute the specifity of a permission to keep the decision of the most specific if two or more permissions overlap
+ specificity = self.compute_specificity(permission=permission)
+ if specificity > highest_specificity:
+ most_specific_permission = permission.decision
+ highest_specificity = specificity
+ elif specificity == highest_specificity and permission.decision == PermissionDecision.DENY.value:
+ most_specific_permission = permission.decision
+
+ return most_specific_permission == PermissionDecision.ALLOW.value
+
+ def resolve_global_permission(self, permissions: list[GlobalPermission], permission_to_check: str) -> bool:
+ if not permission_to_check.startswith("global:"):
+ return False
+
+ _, action, _ = permission_to_check.split(":")
+ grant_permission = False
+
+ for permission in permissions:
+ if permission.action == action:
+ # Early exit on deny as deny preempt allow
+ if permission.decision == PermissionDecision.DENY.value:
+ return False
+ grant_permission = True
+
+ return grant_permission
+
+ async def load_permissions(self, db: InfrahubDatabase, account_id: str, branch: Branch) -> AssignedPermissions:
+ return await fetch_permissions(db=db, account_id=account_id, branch=branch)
+
+ async def has_permission(self, db: InfrahubDatabase, account_id: str, permission: str, branch: Branch) -> bool:
+ granted_permissions = await self.load_permissions(db=db, account_id=account_id, branch=branch)
+
+ # Check for a final super admin permission at the end if no permissions have matched before
+ return (
+ self.resolve_global_permission(
+ permissions=granted_permissions["global_permissions"], permission_to_check=permission
+ )
+ or self.resolve_object_permission(
+ permissions=granted_permissions["object_permissions"], permission_to_check=permission
+ )
+ or self.resolve_global_permission(
+ permissions=granted_permissions["global_permissions"],
+ permission_to_check=f"global:{GlobalPermissions.SUPER_ADMIN.value}:{PermissionDecision.ALLOW.value}",
+ )
+ )
diff --git a/backend/infrahub/permissions/report.py b/backend/infrahub/permissions/report.py
new file mode 100644
index 0000000000..4f6e37d6a0
--- /dev/null
+++ b/backend/infrahub/permissions/report.py
@@ -0,0 +1,59 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from infrahub.core.account import fetch_permissions
+from infrahub.core.constants import GlobalPermissions, PermissionDecision
+from infrahub.core.registry import registry
+from infrahub.permissions.local_backend import LocalPermissionBackend
+
+if TYPE_CHECKING:
+ from infrahub.auth import AccountSession
+ from infrahub.core.branch import Branch
+ from infrahub.core.schema import MainSchemaTypes
+ from infrahub.database import InfrahubDatabase
+ from infrahub.permissions.types import KindPermissions
+
+
+async def report_schema_permissions(
+ db: InfrahubDatabase, schemas: list[MainSchemaTypes], account_session: AccountSession, branch: Branch
+) -> list[KindPermissions]:
+ permissions = await fetch_permissions(account_id=account_session.account_id, db=db, branch=branch)
+ perm_backend = LocalPermissionBackend()
+
+ restrict_changes = False
+ if branch.name == registry.default_branch:
+ restrict_changes = not perm_backend.resolve_global_permission(
+ permissions=permissions["global_permissions"],
+ permission_to_check=f"global:{GlobalPermissions.EDIT_DEFAULT_BRANCH.value}:allow",
+ )
+
+ permission_objects: list[KindPermissions] = []
+
+ for node in schemas:
+ permission_base = f"object:{branch.name}:{node.namespace}:{node.name}"
+
+ has_create = perm_backend.resolve_object_permission(
+ permissions=permissions["object_permissions"], permission_to_check=f"{permission_base}:create:allow"
+ )
+ has_delete = perm_backend.resolve_object_permission(
+ permissions=permissions["object_permissions"], permission_to_check=f"{permission_base}:delete:allow"
+ )
+ has_update = perm_backend.resolve_object_permission(
+ permissions=permissions["object_permissions"], permission_to_check=f"{permission_base}:update:allow"
+ )
+ has_view = perm_backend.resolve_object_permission(
+ permissions=permissions["object_permissions"], permission_to_check=f"{permission_base}:view:allow"
+ )
+
+ permission_objects.append(
+ {
+ "kind": node.kind,
+ "create": PermissionDecision.ALLOW if has_create and not restrict_changes else PermissionDecision.DENY,
+ "delete": PermissionDecision.ALLOW if has_delete and not restrict_changes else PermissionDecision.DENY,
+ "update": PermissionDecision.ALLOW if has_update and not restrict_changes else PermissionDecision.DENY,
+ "view": PermissionDecision.ALLOW if has_view else PermissionDecision.DENY,
+ }
+ )
+
+ return permission_objects
diff --git a/backend/infrahub/permissions/types.py b/backend/infrahub/permissions/types.py
new file mode 100644
index 0000000000..097ed1602e
--- /dev/null
+++ b/backend/infrahub/permissions/types.py
@@ -0,0 +1,14 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, TypedDict
+
+if TYPE_CHECKING:
+ from infrahub.core.constants import PermissionDecision
+
+
+class KindPermissions(TypedDict):
+ kind: str
+ create: PermissionDecision
+ delete: PermissionDecision
+ update: PermissionDecision
+ view: PermissionDecision
diff --git a/backend/infrahub/pools/prefix.py b/backend/infrahub/pools/prefix.py
index 374acef6d4..f28a984f71 100644
--- a/backend/infrahub/pools/prefix.py
+++ b/backend/infrahub/pools/prefix.py
@@ -11,7 +11,7 @@ class PrefixPool:
Class to automatically manage Prefixes and help to carve out sub-prefixes
"""
- def __init__(self, network: str):
+ def __init__(self, network: str) -> None:
self.network = ipaddress.ip_network(network)
# Define biggest and smallest possible masks
diff --git a/backend/infrahub/serve/log.py b/backend/infrahub/serve/log.py
index 18c4f06a25..74c08396b8 100644
--- a/backend/infrahub/serve/log.py
+++ b/backend/infrahub/serve/log.py
@@ -6,7 +6,7 @@
class GunicornLogger(Logger):
- def __init__(self, cfg: Any):
+ def __init__(self, cfg: Any) -> None:
super().__init__(cfg)
self.logger = get_logger("gunicorn")
diff --git a/backend/infrahub/server.py b/backend/infrahub/server.py
index 0ad5f5529d..e7c6ef62ac 100644
--- a/backend/infrahub/server.py
+++ b/backend/infrahub/server.py
@@ -37,6 +37,8 @@
from infrahub.services.adapters.cache.redis import RedisCache
from infrahub.services.adapters.message_bus.nats import NATSMessageBus
from infrahub.services.adapters.message_bus.rabbitmq import RabbitMQMessageBus
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
+from infrahub.services.adapters.workflow.worker import WorkflowWorkerExecution
from infrahub.trace import add_span_exception, configure_trace, get_traceid
from infrahub.worker import WORKER_IDENTITY
@@ -62,6 +64,12 @@ async def app_initialization(application: FastAPI) -> None:
build_component_registry()
+ workflow = config.OVERRIDE.workflow or (
+ WorkflowWorkerExecution()
+ if config.SETTINGS.workflow.driver == config.WorkflowDriver.WORKER
+ else WorkflowLocalExecution()
+ )
+
message_bus = config.OVERRIDE.message_bus or (
NATSMessageBus() if config.SETTINGS.broker.driver == config.BrokerDriver.NATS else RabbitMQMessageBus()
)
@@ -69,7 +77,11 @@ async def app_initialization(application: FastAPI) -> None:
NATSCache() if config.SETTINGS.cache.driver == config.CacheDriver.NATS else RedisCache()
)
service = InfrahubServices(
- cache=cache, database=database, message_bus=message_bus, component_type=ComponentType.API_SERVER
+ cache=cache,
+ database=database,
+ message_bus=message_bus,
+ workflow=workflow,
+ component_type=ComponentType.API_SERVER,
)
await service.initialize()
initialize_lock(service=service)
diff --git a/backend/infrahub/services/__init__.py b/backend/infrahub/services/__init__.py
index 1dd37c2eac..3678bc7b23 100644
--- a/backend/infrahub/services/__init__.py
+++ b/backend/infrahub/services/__init__.py
@@ -13,7 +13,11 @@
from infrahub.message_bus.types import MessageTTL
from .adapters.cache import InfrahubCache
+from .adapters.event import InfrahubEventService
+from .adapters.http import InfrahubHTTP
+from .adapters.http.httpx import HttpxAdapter
from .adapters.message_bus import InfrahubMessageBus
+from .adapters.workflow import InfrahubWorkflow
from .component import InfrahubComponent
from .protocols import InfrahubLogger
from .scheduler import InfrahubScheduler
@@ -26,15 +30,21 @@ def __init__(
client: Optional[InfrahubClient] = None,
database: Optional[InfrahubDatabase] = None,
message_bus: Optional[InfrahubMessageBus] = None,
+ http: InfrahubHTTP | None = None,
+ workflow: Optional[InfrahubWorkflow] = None,
+ event: InfrahubEventService | None = None,
log: Optional[InfrahubLogger] = None,
component_type: Optional[ComponentType] = None,
- ):
+ ) -> None:
self.cache = cache or InfrahubCache()
self._client = client
self._database = database
self.message_bus = message_bus or InfrahubMessageBus()
+ self.workflow = workflow or InfrahubWorkflow()
+ self.event = event or InfrahubEventService()
self.log = log or get_logger()
self.component_type = component_type or ComponentType.NONE
+ self.http = http or HttpxAdapter()
self.scheduler = InfrahubScheduler()
self.component = InfrahubComponent()
@@ -90,10 +100,13 @@ def git_report(
async def initialize(self) -> None:
"""Initialize the Services"""
- await self.component.initialize(service=self)
await self.message_bus.initialize(service=self)
await self.cache.initialize(service=self)
+ await self.http.initialize(service=self)
+ await self.component.initialize(service=self)
await self.scheduler.initialize(service=self)
+ await self.workflow.initialize(service=self)
+ await self.event.initialize(service=self)
async def shutdown(self) -> None:
"""Initialize the Services"""
diff --git a/backend/infrahub/services/adapters/event/__init__.py b/backend/infrahub/services/adapters/event/__init__.py
new file mode 100644
index 0000000000..865778ce08
--- /dev/null
+++ b/backend/infrahub/services/adapters/event/__init__.py
@@ -0,0 +1,46 @@
+from __future__ import annotations
+
+import asyncio
+from typing import TYPE_CHECKING
+
+from prefect.events import emit_event
+
+from infrahub.exceptions import InitializationError
+
+if TYPE_CHECKING:
+ from infrahub.events import InfrahubEvent
+ from infrahub.services import InfrahubServices
+
+
+class InfrahubEventService:
+ """Base class for infrahub event service"""
+
+ def __init__(self) -> None:
+ self._service: InfrahubServices | None = None
+
+ @property
+ def service(self) -> InfrahubServices:
+ if not self._service:
+ raise InitializationError("Event is not initialized with a service")
+
+ return self._service
+
+ async def initialize(self, service: InfrahubServices) -> None:
+ """Initialize the event service"""
+ self._service = service
+
+ async def send(self, event: InfrahubEvent) -> None:
+ tasks = [self._send_bus(event=event), self._send_prefect(event=event)]
+ await asyncio.gather(*tasks)
+
+ async def _send_bus(self, event: InfrahubEvent) -> None:
+ message = event.get_message()
+ await self.service.send(message=message)
+
+ async def _send_prefect(self, event: InfrahubEvent) -> None:
+ emit_event(
+ event=event.get_name(),
+ resource=event.get_resource(),
+ related=event.get_related(),
+ payload=event.get_payload(),
+ )
diff --git a/backend/infrahub/services/adapters/http/__init__.py b/backend/infrahub/services/adapters/http/__init__.py
new file mode 100644
index 0000000000..744715e1d5
--- /dev/null
+++ b/backend/infrahub/services/adapters/http/__init__.py
@@ -0,0 +1,30 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+if TYPE_CHECKING:
+ import httpx
+
+ from infrahub.services import InfrahubServices
+
+
+class InfrahubHTTP:
+ async def initialize(self, service: InfrahubServices) -> None:
+ """Initialize the HTTP adapter"""
+
+ async def get(
+ self,
+ url: str,
+ headers: dict[str, Any] | None = None,
+ ) -> httpx.Response:
+ raise NotImplementedError()
+
+ async def post(
+ self,
+ url: str,
+ data: Any | None = None,
+ json: Any | None = None,
+ headers: dict[str, Any] | None = None,
+ verify: bool | None = None,
+ ) -> httpx.Response:
+ raise NotImplementedError()
diff --git a/backend/infrahub/services/adapters/http/httpx.py b/backend/infrahub/services/adapters/http/httpx.py
new file mode 100644
index 0000000000..26bec3fc8e
--- /dev/null
+++ b/backend/infrahub/services/adapters/http/httpx.py
@@ -0,0 +1,98 @@
+from __future__ import annotations
+
+import ssl
+from functools import cached_property
+from typing import TYPE_CHECKING, Any
+
+import httpx
+
+from infrahub import config
+from infrahub.exceptions import HTTPServerError, HTTPServerSSLError, HTTPServerTimeoutError
+from infrahub.services.adapters.http import InfrahubHTTP
+
+if TYPE_CHECKING:
+ from infrahub.services import InfrahubServices
+
+
+class HttpxAdapter(InfrahubHTTP):
+ settings: config.HTTPSettings
+ service: InfrahubServices
+
+ async def initialize(self, service: InfrahubServices) -> None:
+ """Initialize the HTTP adapter"""
+ self.service = service
+ self.settings = config.SETTINGS.http
+
+ # Cache the context during init, this is to avoid issue when a CA bundle might be accessible
+ # when Infrahub initializes but then removed before the first external HTTP call is made.
+ _ = self.tls_context
+
+ @cached_property
+ def tls_context(self) -> ssl.SSLContext:
+ return self.settings.get_tls_context()
+
+ def verify_tls(self, verify: bool | None = None) -> bool | ssl.SSLContext:
+ if verify is False:
+ return False
+
+ return self.tls_context
+
+ async def _request(
+ self,
+ method: str,
+ url: str,
+ data: Any | None = None,
+ json: Any | None = None,
+ headers: dict[str, Any] | None = None,
+ verify: bool | None = None,
+ ) -> httpx.Response:
+ """Returns an httpx.Response object or raises HTTPServerError or child classes."""
+ params: dict[str, Any] = {}
+ if data:
+ params["data"] = data
+ if json:
+ params["json"] = json
+ async with httpx.AsyncClient(verify=self.verify_tls(verify=verify)) as client:
+ try:
+ response = await client.request(
+ method=method,
+ url=url,
+ headers=headers,
+ timeout=self.settings.timeout,
+ **params,
+ )
+ except ssl.SSLCertVerificationError as exc:
+ self.service.log.info(f"TLS verification failed for connection to {url}")
+ raise HTTPServerSSLError(message=f"Unable to validate TLS certificate for connection to {url}") from exc
+ except httpx.ReadTimeout as exc:
+ self.service.log.info(f"Connection timed out when trying to reach {url}")
+ raise HTTPServerTimeoutError(
+ message=f"Connection to {url} timed out after {self.settings.timeout}"
+ ) from exc
+ except httpx.RequestError as exc:
+ # Catch all error from httpx
+ self.service.log.warning(f"Unhandled HTTP error for {url} ({exc})")
+ raise HTTPServerError(message=f"Unknown http error when connecting to {url}") from exc
+
+ return response
+
+ async def get(
+ self,
+ url: str,
+ headers: dict[str, Any] | None = None,
+ ) -> httpx.Response:
+ return await self._request(
+ method="get",
+ url=url,
+ headers=headers,
+ )
+
+ async def post(
+ self,
+ url: str,
+ data: Any | None = None,
+ json: Any | None = None,
+ headers: dict[str, Any] | None = None,
+ verify: bool | None = None,
+ ) -> httpx.Response:
+ return await self._request(method="post", url=url, data=data, json=json, headers=headers, verify=verify)
diff --git a/backend/infrahub/services/adapters/message_bus/local.py b/backend/infrahub/services/adapters/message_bus/local.py
index 57e55ac3d4..09967080aa 100644
--- a/backend/infrahub/services/adapters/message_bus/local.py
+++ b/backend/infrahub/services/adapters/message_bus/local.py
@@ -21,7 +21,7 @@
class BusSimulator(InfrahubMessageBus):
- def __init__(self, database: Optional[InfrahubDatabase] = None):
+ def __init__(self, database: Optional[InfrahubDatabase] = None) -> None:
self.messages: list[InfrahubMessage] = []
self.messages_per_routing_key: dict[str, list[InfrahubMessage]] = {}
self.service: InfrahubServices = InfrahubServices(database=database, message_bus=self)
diff --git a/backend/infrahub/services/adapters/message_bus/rabbitmq.py b/backend/infrahub/services/adapters/message_bus/rabbitmq.py
index 2ba4421792..053e31b3a2 100644
--- a/backend/infrahub/services/adapters/message_bus/rabbitmq.py
+++ b/backend/infrahub/services/adapters/message_bus/rabbitmq.py
@@ -93,7 +93,7 @@ async def initialize(self, service: InfrahubServices) -> None:
ssl=self.settings.tls_enabled,
ssl_options={
"no_verify_ssl": int(self.settings.tls_insecure),
- "cafile": self.settings.tls_ca_file if self.settings.tls_ca_file else "",
+ "cafile": self.settings.tls_ca_file or "",
},
)
diff --git a/backend/infrahub/services/adapters/workflow/__init__.py b/backend/infrahub/services/adapters/workflow/__init__.py
new file mode 100644
index 0000000000..19aecf5b1c
--- /dev/null
+++ b/backend/infrahub/services/adapters/workflow/__init__.py
@@ -0,0 +1,25 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, ParamSpec, TypeVar
+
+if TYPE_CHECKING:
+ from infrahub.services import InfrahubServices
+ from infrahub.workflows.models import WorkflowDefinition
+
+Return = TypeVar("Return")
+Params = ParamSpec("Params")
+
+FuncType = Callable[Params, Return]
+
+
+class InfrahubWorkflow:
+ async def initialize(self, service: InfrahubServices) -> None:
+ """Initialize the Workflow engine"""
+
+ async def execute(
+ self,
+ workflow: WorkflowDefinition | None = None,
+ function: Callable[..., Awaitable[Return]] | None = None,
+ **kwargs: Any,
+ ) -> Return:
+ raise NotImplementedError()
diff --git a/backend/infrahub/services/adapters/workflow/local.py b/backend/infrahub/services/adapters/workflow/local.py
new file mode 100644
index 0000000000..a917d0d241
--- /dev/null
+++ b/backend/infrahub/services/adapters/workflow/local.py
@@ -0,0 +1,20 @@
+from typing import Any, Awaitable, Callable
+
+from infrahub.workflows.models import WorkflowDefinition
+
+from . import InfrahubWorkflow, Return
+
+
+class WorkflowLocalExecution(InfrahubWorkflow):
+ async def execute(
+ self,
+ workflow: WorkflowDefinition | None = None,
+ function: Callable[..., Awaitable[Return]] | None = None,
+ **kwargs: Any,
+ ) -> Return:
+ if workflow:
+ fn = workflow.get_function()
+ return await fn(**kwargs)
+ if function:
+ return await function(**kwargs)
+ raise ValueError("either a workflow definition or a flow must be provided")
diff --git a/backend/infrahub/services/adapters/workflow/worker.py b/backend/infrahub/services/adapters/workflow/worker.py
new file mode 100644
index 0000000000..55a6ef0d8c
--- /dev/null
+++ b/backend/infrahub/services/adapters/workflow/worker.py
@@ -0,0 +1,45 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Awaitable, Callable
+
+from prefect.client.schemas import StateType
+from prefect.deployments import run_deployment
+
+from infrahub.workflows.initialization import setup_task_manager
+
+from . import InfrahubWorkflow, Return
+
+if TYPE_CHECKING:
+ from prefect.client.schemas.objects import FlowRun
+
+ from infrahub.services import InfrahubServices
+ from infrahub.workflows.models import WorkflowDefinition
+
+
+class WorkflowWorkerExecution(InfrahubWorkflow):
+ async def initialize(self, service: InfrahubServices) -> None:
+ """Initialize the Workflow engine"""
+
+ if await service.component.is_primary_api():
+ await setup_task_manager()
+
+ async def execute(
+ self,
+ workflow: WorkflowDefinition | None = None,
+ function: Callable[..., Awaitable[Return]] | None = None,
+ **kwargs: Any,
+ ) -> Return:
+ if workflow:
+ response: FlowRun = await run_deployment(name=workflow.full_name, parameters=kwargs or {}) # type: ignore[return-value, misc]
+ if not response.state:
+ raise RuntimeError("Unable to read state from the response")
+
+ if response.state.type == StateType.CRASHED:
+ raise RuntimeError(response.state.message)
+
+ return await response.state.result(raise_on_failure=True, fetch=True) # type: ignore[call-overload]
+
+ if function:
+ return await function(**kwargs)
+
+ raise ValueError("either a workflow definition or a flow must be provided")
diff --git a/backend/infrahub/services/component.py b/backend/infrahub/services/component.py
index 0cca32ee80..6f0f20e8eb 100644
--- a/backend/infrahub/services/component.py
+++ b/backend/infrahub/services/component.py
@@ -42,6 +42,8 @@ async def initialize(self, service: InfrahubServices) -> None:
"""Initialize the Message bus"""
self._service = service
+ await self.refresh_heartbeat()
+
async def is_primary_api(self) -> bool:
primary_identity = await self.service.cache.get(PRIMARY_API_SERVER)
return primary_identity == WORKER_IDENTITY
diff --git a/backend/infrahub/tasks/dummy.py b/backend/infrahub/tasks/dummy.py
new file mode 100644
index 0000000000..ef639ddbe0
--- /dev/null
+++ b/backend/infrahub/tasks/dummy.py
@@ -0,0 +1,41 @@
+from prefect import flow, task
+from pydantic import BaseModel
+
+from infrahub.workflows.models import WorkflowDefinition
+
+DUMMY_FLOW = WorkflowDefinition(
+ name="dummy_flow",
+ module="infrahub.tasks.dummy",
+ function="dummy_flow",
+)
+
+DUMMY_FLOW_BROKEN = WorkflowDefinition(
+ name="dummy_flow_broken",
+ module="infrahub.tasks.dummy",
+ function="dummy_flow_broken",
+)
+
+
+class DummyInput(BaseModel):
+ firstname: str
+ lastname: str
+
+
+class DummyOutput(BaseModel):
+ full_name: str
+
+
+@task
+async def aggregate_name(firstname: str, lastname: str) -> str:
+ return f"{firstname}, {lastname}"
+
+
+@flow(persist_result=True)
+async def dummy_flow(data: DummyInput) -> DummyOutput:
+ return DummyOutput(full_name=await aggregate_name(firstname=data.firstname, lastname=data.lastname))
+
+
+@flow(persist_result=True)
+async def dummy_flow_broken(data: DummyInput) -> DummyOutput:
+ response = await aggregate_name(firstname=data.firstname, lastname=data.lastname)
+ return DummyOutput(not_valid=response) # type: ignore[call-arg]
diff --git a/backend/infrahub/test_data/dataset01.py b/backend/infrahub/test_data/dataset01.py
index cfc2dacaf2..f13f2f7fe7 100644
--- a/backend/infrahub/test_data/dataset01.py
+++ b/backend/infrahub/test_data/dataset01.py
@@ -1,5 +1,5 @@
-from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
+from infrahub.core.protocols import CoreGroup
from infrahub.database import InfrahubDatabase
from infrahub.log import get_logger
@@ -74,7 +74,7 @@
log = get_logger()
-async def load_data(db: InfrahubDatabase, nbr_devices: int = None):
+async def load_data(db: InfrahubDatabase, nbr_devices: int = 0) -> None:
# ------------------------------------------
# Create User Accounts and Groups
# ------------------------------------------
@@ -82,7 +82,7 @@ async def load_data(db: InfrahubDatabase, nbr_devices: int = None):
# tags_dict = {}
for group in GROUPS:
- obj = await Node.init(db=db, schema=InfrahubKind.GENERICGROUP)
+ obj = await Node.init(db=db, schema=CoreGroup)
await obj.new(db=db, description=group[0], name=group[1])
await obj.save(db=db)
groups_dict[group[1]] = obj
@@ -112,10 +112,10 @@ async def load_data(db: InfrahubDatabase, nbr_devices: int = None):
role = None
if device[4]:
role = device[4]
- obj = await Node.init(db=db, schema="InfraDevice")
- await obj.new(db=db, name=device[0], status=status, type=device[2], role=role, site=site_hq)
+ device_obj = await Node.init(db=db, schema="InfraDevice")
+ await device_obj.new(db=db, name=device[0], status=status, type=device[2], role=role, site=site_hq)
- await obj.save(db=db)
+ await device_obj.save(db=db)
log.info(f"- Created Device: {device[0]}")
# Add a special interface for spine1
@@ -152,7 +152,7 @@ async def load_data(db: InfrahubDatabase, nbr_devices: int = None):
intf = await Node.init(db=db, schema="InfraInterfaceL3")
await intf.new(
db=db,
- device=obj,
+ device=device_obj,
name=intf_name,
speed=10000,
enabled=enabled,
diff --git a/backend/infrahub/test_data/gen_connected_nodes.py b/backend/infrahub/test_data/gen_connected_nodes.py
index d258f02d84..0af4e284ac 100644
--- a/backend/infrahub/test_data/gen_connected_nodes.py
+++ b/backend/infrahub/test_data/gen_connected_nodes.py
@@ -12,7 +12,7 @@
class GenerateConnectedNodes(DataGenerator):
- async def load_data(self, nbr_tags: int = 50, nbr_repository: int = 100, nbr_query: int = 1000):
+ async def load_data(self, nbr_tags: int = 50, nbr_repository: int = 100, nbr_query: int = 1000) -> None:
"""Generate a large number of GraphQLQuery associated with some Tags and some Repositorie."""
default_branch = await registry.get_branch(db=self.db)
diff --git a/backend/infrahub/test_data/gen_isolated_node.py b/backend/infrahub/test_data/gen_isolated_node.py
index 8dcf06360a..ee768d3336 100644
--- a/backend/infrahub/test_data/gen_isolated_node.py
+++ b/backend/infrahub/test_data/gen_isolated_node.py
@@ -15,7 +15,7 @@ async def load_data(
self,
nbr_tags: int = 100,
nbr_repository: int = 100,
- ):
+ ) -> None:
"""Generate a large number of Tags and Repositories"""
default_branch = await registry.get_branch(db=self.db)
diff --git a/backend/infrahub/test_data/gen_node_profile_node.py b/backend/infrahub/test_data/gen_node_profile_node.py
index e094d46aae..cdad46fb2c 100644
--- a/backend/infrahub/test_data/gen_node_profile_node.py
+++ b/backend/infrahub/test_data/gen_node_profile_node.py
@@ -14,7 +14,7 @@ class ProfileAttribute(DataGenerator):
async def load_data(
self,
nbr_person: int = 100,
- ):
+ ) -> None:
"""Generate a large number of Tags and Repositories"""
default_branch = await registry.get_branch(db=self.db)
diff --git a/backend/infrahub/test_data/shared.py b/backend/infrahub/test_data/shared.py
index 9421263500..6978a12504 100644
--- a/backend/infrahub/test_data/shared.py
+++ b/backend/infrahub/test_data/shared.py
@@ -25,7 +25,7 @@ def __init__(
semaphore: Optional[asyncio.Semaphore] = None,
max_concurrent_execution: int = 5,
return_exceptions: bool = False,
- ):
+ ) -> None:
super().__init__(
semaphore=semaphore, max_concurrent_execution=max_concurrent_execution, return_exceptions=return_exceptions
)
@@ -41,7 +41,9 @@ def add(self, *args: Any, **kwargs: Any) -> None:
class DataGenerator:
- def __init__(self, db: InfrahubDatabase, concurrent_execution: int = 2, progress: Optional[Progress] = None):
+ def __init__(
+ self, db: InfrahubDatabase, concurrent_execution: int = 2, progress: Optional[Progress] = None
+ ) -> None:
self.db = db
self.concurrent_execution = concurrent_execution
self.progress = progress
diff --git a/backend/infrahub/types.py b/backend/infrahub/types.py
index 9ee6ef4006..5b2805d773 100644
--- a/backend/infrahub/types.py
+++ b/backend/infrahub/types.py
@@ -17,7 +17,7 @@
from infrahub.graphql.types.attribute import BaseAttribute as BaseAttributeType
DEFAULT_MODULE_ATTRIBUTE = "infrahub.core.attribute"
-DEFAULT_MODULE_GRAPHQL_INPUT = "infrahub.graphql.mutations"
+DEFAULT_MODULE_GRAPHQL_INPUT = "infrahub.graphql.mutations.attribute"
DEFAULT_MODULE_GRAPHQL_QUERY = "infrahub.graphql.types"
@@ -32,7 +32,7 @@ class InfrahubDataType:
pydantic: type
@classmethod
- def __init_subclass__(cls, **kwargs: typing.Any):
+ def __init_subclass__(cls, **kwargs: typing.Any) -> None:
super().__init_subclass__(**kwargs)
registry.data_type[cls.label] = cls
diff --git a/backend/infrahub/utils.py b/backend/infrahub/utils.py
index 05b97dc44b..0ac995275f 100644
--- a/backend/infrahub/utils.py
+++ b/backend/infrahub/utils.py
@@ -2,6 +2,7 @@
import os
from enum import Enum, EnumMeta
from pathlib import Path
+from re import finditer
from typing import Any, Optional
KWARGS_TO_DROP = ["session"]
@@ -29,6 +30,12 @@ def find_first_file_in_directory(directory: str) -> Optional[str]:
return None
+def extract_camelcase_words(camel_case: str) -> list[str]:
+ """Extract the namespace and the name for a kind given its camel-case form."""
+ matches = finditer(r".+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)", camel_case)
+ return [m.group(0) for m in matches]
+
+
def format_label(slug: str) -> str:
return " ".join([word.title() for word in slug.split("_")])
diff --git a/backend/infrahub/webhook.py b/backend/infrahub/webhook.py
index c0136ff716..ee308cd78a 100644
--- a/backend/infrahub/webhook.py
+++ b/backend/infrahub/webhook.py
@@ -6,7 +6,6 @@
from typing import Any, Optional, Union
from uuid import uuid4
-import httpx
from pydantic import BaseModel, ConfigDict, Field
from infrahub.core.constants import InfrahubKind
@@ -37,8 +36,7 @@ def webhook_type(self) -> str:
async def send(self) -> None:
await self._prepare_payload()
self._assign_headers()
- async with httpx.AsyncClient(verify=self.validate_certificates) as client:
- await client.post(self.url, json=self._payload, headers=self._headers)
+ await self.service.http.post(url=self.url, json=self._payload, headers=self._headers)
class CustomWebhook(Webhook):
diff --git a/sync/examples/ipfabric_to_infrahub/ipfabricsync/__init__.py b/backend/infrahub/workers/__init__.py
similarity index 100%
rename from sync/examples/ipfabric_to_infrahub/ipfabricsync/__init__.py
rename to backend/infrahub/workers/__init__.py
diff --git a/backend/infrahub/workers/infrahub_async.py b/backend/infrahub/workers/infrahub_async.py
new file mode 100644
index 0000000000..85d6a9b00c
--- /dev/null
+++ b/backend/infrahub/workers/infrahub_async.py
@@ -0,0 +1,160 @@
+import importlib
+import logging
+import os
+from typing import Any, Optional
+
+import typer
+from anyio.abc import TaskStatus
+from infrahub_sdk import Config, InfrahubClient
+from infrahub_sdk.exceptions import Error as SdkError
+from prefect import settings as prefect_settings
+from prefect.client.schemas.objects import FlowRun
+from prefect.flow_engine import run_flow_async
+from prefect.workers.base import BaseJobConfiguration, BaseVariables, BaseWorker, BaseWorkerResult
+from prometheus_client import start_http_server
+
+from infrahub import config
+from infrahub.components import ComponentType
+from infrahub.core.initialization import initialization
+from infrahub.database import InfrahubDatabase, get_db
+from infrahub.dependencies.registry import build_component_registry
+from infrahub.git import initialize_repositories_directory
+from infrahub.lock import initialize_lock
+from infrahub.services import InfrahubServices, services
+from infrahub.services.adapters.cache.nats import NATSCache
+from infrahub.services.adapters.cache.redis import RedisCache
+from infrahub.services.adapters.message_bus.nats import NATSMessageBus
+from infrahub.services.adapters.message_bus.rabbitmq import RabbitMQMessageBus
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
+from infrahub.services.adapters.workflow.worker import WorkflowWorkerExecution
+from infrahub.workflows.models import TASK_RESULT_STORAGE_NAME
+
+
+class InfrahubWorkerAsyncConfiguration(BaseJobConfiguration):
+ pass
+
+
+class InfrahubWorkerAsyncTemplateVariables(BaseVariables):
+ pass
+
+
+class InfrahubWorkerAsyncResult(BaseWorkerResult):
+ """Result returned by the InfrahubWorker."""
+
+
+class InfrahubWorkerAsync(BaseWorker):
+ type: str = "infrahubasync"
+ job_configuration = InfrahubWorkerAsyncConfiguration
+ job_configuration_variables = InfrahubWorkerAsyncTemplateVariables
+ _documentation_url = "https://example.com/docs"
+ _logo_url = "https://example.com/logo"
+ _description = "Infrahub worker designed to run the flow in the main async loop."
+
+ async def setup(self, **kwargs: dict[str, Any]) -> None:
+ logging.getLogger("websockets").setLevel(logging.ERROR)
+ logging.getLogger("httpx").setLevel(logging.ERROR)
+ logging.getLogger("httpcore").setLevel(logging.ERROR)
+ logging.getLogger("neo4j").setLevel(logging.ERROR)
+ logging.getLogger("aio_pika").setLevel(logging.ERROR)
+ logging.getLogger("aiormq").setLevel(logging.ERROR)
+ logging.getLogger("git").setLevel(logging.ERROR)
+
+ config_file = os.environ.get("INFRAHUB_CONFIG", "infrahub.toml")
+ config.load_and_exit(config_file_name=config_file)
+
+ # Start metric endpoint on port 8000
+ metric_port = int(os.environ.get("INFRAHUB_METRICS_PORT", 8000))
+ self._logger.info(f"Starting metric endpoint on port {metric_port}")
+ start_http_server(metric_port)
+
+ self._exit_stack.enter_context(
+ prefect_settings.temporary_settings(
+ updates={ # type: ignore[arg-type]
+ prefect_settings.PREFECT_WORKER_QUERY_SECONDS: config.SETTINGS.workflow.worker_polling_interval,
+ prefect_settings.PREFECT_RESULTS_PERSIST_BY_DEFAULT: True,
+ prefect_settings.PREFECT_DEFAULT_RESULT_STORAGE_BLOCK: f"redisstoragecontainer/{TASK_RESULT_STORAGE_NAME}",
+ }
+ )
+ )
+
+ await super().setup(**kwargs)
+
+ self._logger.debug(f"Using Infrahub API at {config.SETTINGS.main.internal_address}")
+ client = InfrahubClient(
+ config=Config(address=config.SETTINGS.main.internal_address, retry_on_failure=True, log=self._logger)
+ )
+ try:
+ await client.branch.all()
+ except SdkError as exc:
+ self._logger.error(f"Error in communication with Infrahub: {exc.message}")
+ raise typer.Exit(1)
+
+ database = InfrahubDatabase(driver=await get_db(retry=1))
+
+ workflow = config.OVERRIDE.workflow or (
+ WorkflowWorkerExecution()
+ if config.SETTINGS.workflow.driver == config.WorkflowDriver.WORKER
+ else WorkflowLocalExecution()
+ )
+
+ message_bus = config.OVERRIDE.message_bus or (
+ NATSMessageBus() if config.SETTINGS.broker.driver == config.BrokerDriver.NATS else RabbitMQMessageBus()
+ )
+ cache = config.OVERRIDE.cache or (
+ NATSCache() if config.SETTINGS.cache.driver == config.CacheDriver.NATS else RedisCache()
+ )
+
+ service = InfrahubServices(
+ cache=cache,
+ client=client,
+ database=database,
+ message_bus=message_bus,
+ workflow=workflow,
+ component_type=ComponentType.GIT_AGENT,
+ )
+ services.service = service
+
+ await service.initialize()
+
+ # Initialize the lock
+ initialize_lock(service=service)
+
+ async with service.database.start_session() as db:
+ await initialization(db=db)
+
+ await service.component.refresh_schema_hash()
+
+ initialize_repositories_directory()
+ build_component_registry()
+ self._logger.info("Worker initialization completed .. ")
+
+ async def run(
+ self,
+ flow_run: FlowRun,
+ configuration: BaseJobConfiguration,
+ task_status: Optional[TaskStatus] = None,
+ ) -> BaseWorkerResult:
+ flow_run_logger = self.get_flow_run_logger(flow_run)
+
+ entrypoint: str = configuration._related_objects["deployment"].entrypoint
+
+ file_path, flow_name = entrypoint.split(":")
+ file_path.replace("/", ".")
+ module_path = file_path.replace("backend/", "").replace(".py", "").replace("/", ".")
+ module = importlib.import_module(module_path)
+
+ flow_func = getattr(module, flow_name)
+
+ flow_run_logger.debug("Validating parameters")
+ params = flow_func.validate_parameters(parameters=flow_run.parameters)
+
+ if task_status:
+ task_status.started()
+
+ await run_flow_async(flow=flow_func, flow_run=flow_run, parameters=params, return_type="state")
+
+ # exit_code = job_status.exit_code if job_status else -1 # Get result of execution for reporting
+ return InfrahubWorkerAsyncResult(
+ status_code=0,
+ identifier=str(flow_run.id),
+ )
diff --git a/sync/examples/librenms_to_infrahub/infrahub/__init__.py b/backend/infrahub/workflows/__init__.py
similarity index 100%
rename from sync/examples/librenms_to_infrahub/infrahub/__init__.py
rename to backend/infrahub/workflows/__init__.py
diff --git a/backend/infrahub/workflows/catalogue.py b/backend/infrahub/workflows/catalogue.py
new file mode 100644
index 0000000000..412b68aaf3
--- /dev/null
+++ b/backend/infrahub/workflows/catalogue.py
@@ -0,0 +1,52 @@
+from .constants import WorkflowType
+from .models import WorkerPoolDefinition, WorkflowDefinition
+
+INFRAHUB_WORKER_POOL = WorkerPoolDefinition(
+ name="infrahub-worker", worker_type="infrahubasync", description="Default Pool for internal tasks"
+)
+
+WEBHOOK_SEND = WorkflowDefinition(
+ name="webhook_send",
+ type=WorkflowType.USER,
+ module="infrahub.message_bus.operations.send.webhook",
+ function="send_webhook",
+)
+
+TRANSFORM_JINJA2_RENDER = WorkflowDefinition(
+ name="transform_render_jinja2_template",
+ type=WorkflowType.USER,
+ module="infrahub.message_bus.operations.transform.jinja",
+ function="transform_render_jinja2_template",
+)
+
+ANONYMOUS_TELEMETRY_SEND = WorkflowDefinition(
+ name="anonymous_telemetry_send",
+ type=WorkflowType.INTERNAL,
+ cron="0 2 * * *",
+ module="infrahub.message_bus.operations.send.telemetry",
+ function="send_telemetry_push",
+)
+
+SCHEMA_APPLY_MIGRATION = WorkflowDefinition(
+ name="schema_apply_migrations",
+ type=WorkflowType.INTERNAL,
+ module="infrahub.core.migrations.schema.tasks",
+ function="schema_apply_migrations",
+)
+
+SCHEMA_VALIDATE_MIGRATION = WorkflowDefinition(
+ name="schema_validate_migrations",
+ type=WorkflowType.INTERNAL,
+ module="infrahub.core.validators.tasks",
+ function="schema_validate_migrations",
+)
+
+worker_pools = [INFRAHUB_WORKER_POOL]
+
+workflows = [
+ WEBHOOK_SEND,
+ TRANSFORM_JINJA2_RENDER,
+ ANONYMOUS_TELEMETRY_SEND,
+ SCHEMA_APPLY_MIGRATION,
+ SCHEMA_VALIDATE_MIGRATION,
+]
diff --git a/backend/infrahub/workflows/constants.py b/backend/infrahub/workflows/constants.py
new file mode 100644
index 0000000000..ff650c935d
--- /dev/null
+++ b/backend/infrahub/workflows/constants.py
@@ -0,0 +1,6 @@
+from infrahub.utils import InfrahubStringEnum
+
+
+class WorkflowType(InfrahubStringEnum):
+ INTERNAL = "internal"
+ USER = "user"
diff --git a/backend/infrahub/workflows/initialization.py b/backend/infrahub/workflows/initialization.py
new file mode 100644
index 0000000000..e7c42ae356
--- /dev/null
+++ b/backend/infrahub/workflows/initialization.py
@@ -0,0 +1,68 @@
+from prefect import flow, task
+from prefect.blocks.redis import RedisStorageContainer
+from prefect.client.orchestration import PrefectClient, get_client
+from prefect.client.schemas.actions import WorkPoolCreate
+from prefect.exceptions import ObjectAlreadyExists
+from prefect.logging import get_run_logger
+
+from infrahub import config
+
+from .catalogue import worker_pools, workflows
+from .models import TASK_RESULT_STORAGE_NAME
+
+
+@task(name="task-manager-setup-worker-pools")
+async def setup_worker_pools(client: PrefectClient) -> None:
+ log = get_run_logger()
+ for worker in worker_pools:
+ wp = WorkPoolCreate(
+ name=worker.name,
+ type=worker.worker_type,
+ description=worker.description,
+ )
+ try:
+ await client.create_work_pool(work_pool=wp)
+ log.info(f"Work pool {worker.name} created successfully ... ")
+ except ObjectAlreadyExists:
+ log.warning(f"Work pool {worker.name} already present ")
+
+
+@task(name="task-manager-setup-deployments")
+async def setup_deployments(client: PrefectClient) -> None:
+ log = get_run_logger()
+ for workflow in workflows:
+ # For now the workpool is hardcoded but
+ # later we need to make it dynamic to have a different worker based on the type of the workflow
+ work_pool = worker_pools[0]
+ await workflow.save(client=client, work_pool=work_pool)
+ log.info(f"Flow {workflow.name}, created successfully ... ")
+
+
+@task(name="task-manager-setup-blocks")
+async def setup_blocks() -> None:
+ log = get_run_logger()
+
+ try:
+ await RedisStorageContainer.register_type_and_schema()
+ except ObjectAlreadyExists:
+ log.warning(f"Redis Storage {TASK_RESULT_STORAGE_NAME} already registered ")
+
+ redis_block = RedisStorageContainer.from_host(
+ host=config.SETTINGS.cache.address,
+ port=config.SETTINGS.cache.service_port,
+ db=config.SETTINGS.cache.database,
+ username=config.SETTINGS.cache.username or None,
+ password=config.SETTINGS.cache.password or None,
+ )
+ try:
+ await redis_block.save(name=TASK_RESULT_STORAGE_NAME, overwrite=True)
+ except ObjectAlreadyExists:
+ log.warning(f"Redis Storage {TASK_RESULT_STORAGE_NAME} already present ")
+
+
+@flow(name="task-manager-setup")
+async def setup_task_manager() -> None:
+ async with get_client(sync_client=False) as client:
+ await setup_blocks()
+ await setup_worker_pools(client=client)
+ await setup_deployments(client=client)
diff --git a/backend/infrahub/workflows/models.py b/backend/infrahub/workflows/models.py
new file mode 100644
index 0000000000..04618be11a
--- /dev/null
+++ b/backend/infrahub/workflows/models.py
@@ -0,0 +1,60 @@
+import importlib
+from typing import Any, Awaitable, Callable, Optional
+from uuid import UUID
+
+from prefect.client.orchestration import PrefectClient
+from prefect.client.schemas.actions import DeploymentScheduleCreate
+from prefect.client.schemas.schedules import CronSchedule
+from pydantic import BaseModel
+
+from infrahub import __version__
+
+from .constants import WorkflowType
+
+TASK_RESULT_STORAGE_NAME = "infrahub-storage"
+
+
+class WorkerPoolDefinition(BaseModel):
+ name: str
+ worker_type: str
+ description: str = ""
+
+
+class WorkflowDefinition(BaseModel):
+ name: str
+ type: WorkflowType = WorkflowType.INTERNAL
+ module: str
+ function: str
+ cron: Optional[str] = None
+
+ @property
+ def entrypoint(self) -> str:
+ return f'backend/{self.module.replace(".", "/")}:{self.function}'
+
+ @property
+ def full_name(self) -> str:
+ return f"{self.name}/{self.name}"
+
+ def to_deployment(self) -> dict[str, Any]:
+ payload: dict[str, Any] = {
+ "name": self.name,
+ "entrypoint": self.entrypoint,
+ }
+ if self.type == WorkflowType.INTERNAL:
+ payload["version"] = __version__
+ if self.cron:
+ payload["schedules"] = [DeploymentScheduleCreate(schedule=CronSchedule(cron=self.cron))]
+ return payload
+
+ async def save(self, client: PrefectClient, work_pool: WorkerPoolDefinition) -> UUID:
+ flow_id = await client.create_flow_from_name(self.name)
+ data = self.to_deployment()
+ data["work_pool_name"] = work_pool.name
+ return await client.create_deployment(flow_id=flow_id, **data)
+
+ def get_function(self) -> Callable[..., Awaitable[Any]]:
+ module = importlib.import_module(self.module)
+ return getattr(module, self.function)
+
+ def validate_workflow(self) -> None:
+ self.get_function()
diff --git a/backend/templates/relationshipschema_imports.j2 b/backend/templates/relationshipschema_imports.j2
index 974c8e45a4..ef8421fc66 100644
--- a/backend/templates/relationshipschema_imports.j2
+++ b/backend/templates/relationshipschema_imports.j2
@@ -1,5 +1,7 @@
-from typing import Optional
+from typing import Optional, TYPE_CHECKING
from infrahub.core.constants import AllowOverrideType, BranchSupportType, RelationshipKind, RelationshipCardinality, RelationshipDeleteBehavior, RelationshipDirection, HashableModelState # noqa: TCH001
from infrahub.core.models import HashableModel
-from infrahub.core.schema.filter import FilterSchema # noqa: TCH001
+
+if TYPE_CHECKING:
+ from infrahub.core.schema.filter import FilterSchema # noqa: TCH001
diff --git a/backend/tests/adapters/message_bus.py b/backend/tests/adapters/message_bus.py
index 441df9d895..abf39be12a 100644
--- a/backend/tests/adapters/message_bus.py
+++ b/backend/tests/adapters/message_bus.py
@@ -18,7 +18,7 @@
class BusRecorder(InfrahubMessageBus):
- def __init__(self, component_type: Optional[ComponentType] = None):
+ def __init__(self, component_type: Optional[ComponentType] = None) -> None:
self.messages: list[InfrahubMessage] = []
self.messages_per_routing_key: dict[str, list[InfrahubMessage]] = {}
@@ -36,7 +36,7 @@ def seen_routing_keys(self) -> list[str]:
class BusSimulator(InfrahubMessageBus):
- def __init__(self, database: Optional[InfrahubDatabase] = None):
+ def __init__(self, database: Optional[InfrahubDatabase] = None) -> None:
self.messages: list[InfrahubMessage] = []
self.messages_per_routing_key: dict[str, list[InfrahubMessage]] = {}
self.service: InfrahubServices = InfrahubServices(database=database, message_bus=self)
@@ -50,7 +50,7 @@ async def publish(
if routing_key not in self.messages_per_routing_key:
self.messages_per_routing_key[routing_key] = []
self.messages_per_routing_key[routing_key].append(message)
- await execute_message(routing_key=routing_key, message_body=message.body, service=self.service)
+ await execute_message(routing_key=routing_key, message_body=message.body, service=self.service, skip_flow=True)
async def reply(self, message: InfrahubMessage, routing_key: str) -> None:
correlation_id = message.meta.correlation_id or "default"
diff --git a/backend/tests/benchmark/test_graphql_query.py b/backend/tests/benchmark/test_graphql_query.py
index e2d3d41c8f..299c049605 100644
--- a/backend/tests/benchmark/test_graphql_query.py
+++ b/backend/tests/benchmark/test_graphql_query.py
@@ -15,10 +15,11 @@
core_models,
internal_schema,
)
-from infrahub.core.schema_manager import SchemaBranch, SchemaManager
+from infrahub.core.schema.manager import SchemaManager
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.utils import delete_all_nodes
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.test_data.dataset04 import load_data
NBR_WARMUP = int(os.getenv("INFRAHUB_BENCHMARK_NBR_WARMUP", 5))
diff --git a/backend/tests/benchmark/test_load_node_to_db.py b/backend/tests/benchmark/test_load_node_to_db.py
index 01f284eabc..de118375d7 100644
--- a/backend/tests/benchmark/test_load_node_to_db.py
+++ b/backend/tests/benchmark/test_load_node_to_db.py
@@ -4,7 +4,7 @@
SchemaRoot,
internal_schema,
)
-from infrahub.core.schema_manager import SchemaManager
+from infrahub.core.schema.manager import SchemaManager
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py
index c1255f0cea..7a92675924 100644
--- a/backend/tests/conftest.py
+++ b/backend/tests/conftest.py
@@ -2,6 +2,8 @@
import importlib
import os
import sys
+import time
+from contextlib import ExitStack
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Any, AsyncGenerator, Generator, Optional, TypeVar
@@ -9,8 +11,16 @@
import pytest
import ujson
from infrahub_sdk.utils import str_to_bool
+from neo4j import GraphDatabase
+from neo4j.exceptions import ServiceUnavailable
+from prefect import settings as prefect_settings
+from prefect.logging.loggers import disable_run_logger
+from prefect.testing.utilities import prefect_test_harness
+from testcontainers.core.container import DockerContainer
+from testcontainers.core.waiting_utils import wait_for_logs
from infrahub import config
+from infrahub.config import load_and_exit
from infrahub.core import registry
from infrahub.core.branch import Branch
from infrahub.core.constants import BranchSupportType, InfrahubKind
@@ -23,7 +33,8 @@
from infrahub.core.node import Node
from infrahub.core.schema import SchemaRoot, core_models, internal_schema
from infrahub.core.schema.definitions.core import core_profile_schema_definition
-from infrahub.core.schema_manager import SchemaBranch, SchemaManager
+from infrahub.core.schema.manager import SchemaManager
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.utils import delete_all_nodes
from infrahub.database import InfrahubDatabase, get_db
from infrahub.lock import initialize_lock
@@ -34,9 +45,15 @@
from tests.adapters.log import FakeLogger
from tests.adapters.message_bus import BusRecorder, BusSimulator
-BUILD_NAME = os.environ.get("INFRAHUB_BUILD_NAME", "infrahub")
-TEST_IN_DOCKER = str_to_bool(os.environ.get("INFRAHUB_TEST_IN_DOCKER", "false"))
ResponseClass = TypeVar("ResponseClass")
+INFRAHUB_USE_TEST_CONTAINERS = str_to_bool(os.getenv("INFRAHUB_USE_TEST_CONTAINERS", "true"))
+PORT_NATS = 4222
+PORT_REDIS = 6379
+PORT_CLIENT_RABBITMQ = 5672
+PORT_HTTP_RABBITMQ = 15672
+PORT_BOLT_NEO4J = 7687
+PORT_MEMGRAPH = 7687
+PORT_PREFECT = 4200
def pytest_addoption(parser):
@@ -70,8 +87,18 @@ def event_loop():
@pytest.fixture(scope="module")
-async def db() -> AsyncGenerator[InfrahubDatabase, None]:
- driver = InfrahubDatabase(driver=await get_db(retry=1))
+async def db(
+ neo4j: Optional[dict[int, int]], memgraph: Optional[dict[int, int]], reload_settings_before_each_module
+) -> AsyncGenerator[InfrahubDatabase, None]:
+ if INFRAHUB_USE_TEST_CONTAINERS:
+ config.SETTINGS.database.address = "localhost"
+ if neo4j is not None:
+ config.SETTINGS.database.port = neo4j[PORT_BOLT_NEO4J]
+ else:
+ assert memgraph is not None
+ config.SETTINGS.database.port = memgraph[PORT_MEMGRAPH]
+
+ driver = InfrahubDatabase(driver=await get_db(retry=5))
yield driver
@@ -133,27 +160,257 @@ async def register_core_models_schema(default_branch: Branch, register_internal_
return schema_branch
+@pytest.fixture(scope="session")
+def prefect_test_fixture():
+ with prefect_test_harness():
+ yield
+
+
+@pytest.fixture(scope="session")
+def prefect_test(prefect_test_fixture):
+ with disable_run_logger():
+ yield
+
+
+def get_exposed_port(container: DockerContainer, port: int) -> int:
+ """
+ Use this method instead of DockerContainer.get_exposed_port as it is decorated with wait_container_is_ready
+ which we do not want to use as it does not perform a real healthcheck. DockerContainer.get_exposed_port
+ also introduces extra "Waiting for container" logs as we might call it multiple times for containers exposing
+ multiple ports such as rabbitmq.
+ """
+
+ return int(container.get_docker_client().port(container.get_wrapped_container().id, port))
+
+
+@pytest.fixture(scope="session")
+def neo4j(request: pytest.FixtureRequest, load_settings_before_session) -> Optional[dict[int, int]]:
+ if not INFRAHUB_USE_TEST_CONTAINERS or config.SETTINGS.database.db_type == "memgraph":
+ return None
+
+ container = (
+ DockerContainer(image=os.getenv("NEO4J_DOCKER_IMAGE", "neo4j:5.20.0-enterprise"))
+ .with_env("NEO4J_AUTH", "neo4j/admin")
+ .with_env("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes")
+ .with_env("NEO4J_dbms_security_procedures_unrestricted", "apoc.*")
+ .with_env("NEO4J_dbms_security_auth__minimum__password__length", "4")
+ .with_exposed_ports(PORT_BOLT_NEO4J)
+ )
+
+ def cleanup():
+ container.stop()
+
+ container.start()
+ wait_for_logs(container, "Started.") # wait_container_is_ready does not seem to be enough
+ request.addfinalizer(cleanup)
+
+ return {PORT_BOLT_NEO4J: get_exposed_port(container, PORT_BOLT_NEO4J)}
+
+
+@pytest.fixture(scope="session")
+def rabbitmq_container(request: pytest.FixtureRequest, load_settings_before_session) -> dict[int, int] | None:
+ if not INFRAHUB_USE_TEST_CONTAINERS or config.SETTINGS.broker.driver != config.BrokerDriver.RabbitMQ:
+ return None
+
+ container = (
+ DockerContainer(image="rabbitmq:3.13.1-management")
+ .with_env("RABBITMQ_DEFAULT_USER", "infrahub")
+ .with_env("RABBITMQ_DEFAULT_PASS", "infrahub")
+ .with_exposed_ports(PORT_CLIENT_RABBITMQ, PORT_HTTP_RABBITMQ)
+ )
+
+ def cleanup():
+ container.stop()
+
+ container.start()
+ wait_for_logs(container, "Server startup complete;") # wait_container_is_ready does not seem to be enough
+ request.addfinalizer(cleanup)
+
+ return {
+ PORT_CLIENT_RABBITMQ: get_exposed_port(container, PORT_CLIENT_RABBITMQ),
+ PORT_HTTP_RABBITMQ: get_exposed_port(container, PORT_HTTP_RABBITMQ),
+ }
+
+
+@pytest.fixture(scope="module")
+def rabbitmq(rabbitmq_container: dict[int, int] | None, reload_settings_before_each_module) -> dict[int, int] | None:
+ if (
+ rabbitmq_container
+ and INFRAHUB_USE_TEST_CONTAINERS
+ and config.SETTINGS.broker.driver == config.BrokerDriver.RabbitMQ
+ ):
+ config.SETTINGS.broker.address = "localhost"
+ config.SETTINGS.broker.port = rabbitmq_container[PORT_CLIENT_RABBITMQ]
+ config.SETTINGS.broker.rabbitmq_http_port = rabbitmq_container[PORT_HTTP_RABBITMQ]
+ return rabbitmq_container
+
+ return None
+
+
+# NOTE: This fixture needs to run before initialize_lock_fixture which is guaranteed to run after as it has a module scope.
+@pytest.fixture(scope="session")
+def redis_container(request: pytest.FixtureRequest, load_settings_before_session) -> dict[int, int] | None:
+ if not INFRAHUB_USE_TEST_CONTAINERS or config.SETTINGS.cache.driver != config.CacheDriver.Redis:
+ return None
+
+ container = DockerContainer(image="redis:latest").with_exposed_ports(PORT_REDIS)
+
+ def cleanup():
+ container.stop()
+
+ container.start()
+ wait_for_logs(container, "Ready to accept connections tcp") # wait_container_is_ready does not seem to be enough
+ request.addfinalizer(cleanup)
+
+ return {PORT_REDIS: get_exposed_port(container, PORT_REDIS)}
+
+
+@pytest.fixture(scope="module")
+def redis(redis_container: dict[int, int] | None, reload_settings_before_each_module) -> dict[int, int] | None:
+ if redis_container and INFRAHUB_USE_TEST_CONTAINERS and config.SETTINGS.cache.driver == config.CacheDriver.Redis:
+ config.SETTINGS.cache.address = "localhost"
+ config.SETTINGS.cache.port = redis_container[PORT_REDIS]
+ config.SETTINGS.cache.username = ""
+ config.SETTINGS.cache.password = ""
+
+ return redis_container
+
+ return None
+
+
+def wait_for_memgraph_ready(host, port, timeout=15):
+ # Not retrieving host/port from config.SETTINGS here as they are set later in `db`fixture.
+ URI = f"{config.SETTINGS.database.protocol}://{host}:{port}"
+
+ start_time = time.time()
+
+ with GraphDatabase.driver(URI) as client:
+ while time.time() - start_time < timeout:
+ try:
+ client.verify_connectivity()
+ return True
+ except ServiceUnavailable:
+ time.sleep(1)
+
+ raise TimeoutError(f"memgraph took more than {timeout} seconds to start.")
+
+
+@pytest.fixture(scope="session")
+def memgraph(request: pytest.FixtureRequest, load_settings_before_session) -> Optional[dict[int, int]]:
+ if not INFRAHUB_USE_TEST_CONTAINERS or config.SETTINGS.database.db_type != "memgraph":
+ return None
+
+ memgraph_image = os.getenv("MEMGRAPH_DOCKER_IMAGE", "memgraph/memgraph-mage:1.19-memgraph-2.19-no-ml")
+
+ container = (
+ DockerContainer(image=memgraph_image, init=True)
+ .with_env("APP_CYPHER_QUERY_MAX_LEN", 10000)
+ .with_exposed_ports(PORT_MEMGRAPH)
+ )
+
+ def cleanup():
+ container.stop()
+
+ container.start()
+
+ # Waiting for logs is not enough to make sure memgraph is available.
+ # Here we need to use DockerContainer.get_exposed_port instead of our own get_exposed_port
+ # in order to wait for the port to be exposed. This call is responsible for "Waiting for memgraph to be ready" logs.
+ # Note we still need to call wait_for_memgraph_ready to be sure the container is fully started.
+ wait_for_memgraph_ready(host="localhost", port=container.get_exposed_port(PORT_MEMGRAPH))
+
+ request.addfinalizer(cleanup)
+
+ return {PORT_MEMGRAPH: get_exposed_port(container, PORT_MEMGRAPH)}
+
+
+@pytest.fixture(scope="session")
+def nats_container(request: pytest.FixtureRequest, load_settings_before_session) -> Optional[dict[int, int]]:
+ if not INFRAHUB_USE_TEST_CONTAINERS or config.SETTINGS.cache.driver != config.CacheDriver.NATS:
+ return None
+
+ container = DockerContainer(image="nats:alpine").with_command("--jetstream").with_exposed_ports(PORT_NATS)
+
+ def cleanup():
+ container.stop()
+
+ container.start()
+ wait_for_logs(container, "Server is ready") # wait_container_is_ready does not seem to be enough
+ request.addfinalizer(cleanup)
+
+ return {PORT_NATS: get_exposed_port(container, PORT_NATS)}
+
+
+@pytest.fixture(scope="module")
+def nats(nats_container: dict[int, int] | None, reload_settings_before_each_module) -> dict[int, int] | None:
+ if nats_container and INFRAHUB_USE_TEST_CONTAINERS and config.SETTINGS.cache.driver == config.CacheDriver.NATS:
+ config.SETTINGS.cache.address = "localhost"
+ config.SETTINGS.cache.port = nats_container[PORT_NATS]
+
+ if nats_container and INFRAHUB_USE_TEST_CONTAINERS and config.SETTINGS.broker.driver == config.BrokerDriver.NATS:
+ config.SETTINGS.broker.address = "localhost"
+ config.SETTINGS.broker.port = nats_container[PORT_NATS]
+
+ return nats_container
+
+ return None
+
+
+@pytest.fixture(scope="session")
+def prefect_container(request: pytest.FixtureRequest, load_settings_before_session) -> Optional[dict[int, int]]:
+ if not INFRAHUB_USE_TEST_CONTAINERS:
+ return None
+
+ container = (
+ DockerContainer(image="prefecthq/prefect:3.0.3-python3.12")
+ .with_command("prefect server start --host 0.0.0.0 --ui")
+ .with_exposed_ports(PORT_PREFECT)
+ )
+
+ def cleanup():
+ container.stop()
+
+ container.start()
+ wait_for_logs(container, "Configure Prefect to communicate with the server")
+ request.addfinalizer(cleanup)
+
+ return {PORT_PREFECT: get_exposed_port(container, PORT_PREFECT)}
+
+
+@pytest.fixture(scope="module")
+def prefect(prefect_container: dict[int, int] | None, reload_settings_before_each_module) -> Generator[str, None, None]:
+ if prefect_container:
+ server_port = prefect_container[PORT_PREFECT]
+ server_api_url = f"http://localhost:{server_port}/api"
+ else:
+ server_api_url = f"http://localhost:{PORT_PREFECT}/api"
+
+ with ExitStack() as stack:
+ stack.enter_context(
+ prefect_settings.temporary_settings(
+ updates={
+ prefect_settings.PREFECT_API_URL: server_api_url,
+ }
+ )
+ )
+ yield server_api_url
+
+
+@pytest.fixture(scope="session", autouse=True)
+def load_settings_before_session():
+ load_and_exit()
+
+
@pytest.fixture(scope="module", autouse=True)
-def execute_before_any_test(worker_id, tmpdir_factory):
- config.load_and_exit()
+def reload_settings_before_each_module(tmpdir_factory):
+ # Settings need to be reloaded between each test module, as some module might modify settings that might break tests within other modules.
+ load_and_exit()
+ # Other settings
config.SETTINGS.storage.driver = config.StorageDriver.FileSystemStorage
- if TEST_IN_DOCKER:
- try:
- db_id = int(worker_id[2]) + 1
- except (ValueError, IndexError):
- db_id = 1
-
- config.SETTINGS.cache.address = f"{BUILD_NAME}-cache-{db_id}"
- if config.SETTINGS.cache.driver == config.CacheDriver.NATS:
- config.SETTINGS.cache.address = f"{BUILD_NAME}-message-queue-{db_id}"
- config.SETTINGS.database.address = f"{BUILD_NAME}-database-{db_id}"
- config.SETTINGS.broker.address = f"{BUILD_NAME}-message-queue-{db_id}"
- config.SETTINGS.storage.local = config.FileSystemStorageSettings(path="/opt/infrahub/storage")
- else:
- storage_dir = tmpdir_factory.mktemp("storage")
- config.SETTINGS.storage.local._path = str(storage_dir)
+ storage_dir = tmpdir_factory.mktemp("storage")
+ config.SETTINGS.storage.local.path_ = str(storage_dir)
config.SETTINGS.broker.enable = False
config.SETTINGS.cache.enable = True
@@ -162,7 +419,7 @@ def execute_before_any_test(worker_id, tmpdir_factory):
config.SETTINGS.main.internal_address = "http://mock"
config.OVERRIDE.message_bus = BusRecorder()
- initialize_lock()
+ initialize_lock(local_only=True)
@pytest.fixture
diff --git a/backend/tests/fixtures/schemas/core_schema_01.json b/backend/tests/fixtures/schemas/core_schema_01.json
index 05f96e3f1b..25cbcae155 100644
--- a/backend/tests/fixtures/schemas/core_schema_01.json
+++ b/backend/tests/fixtures/schemas/core_schema_01.json
@@ -40,18 +40,6 @@
"optional": true,
"cardinality": "one"
}
- ],
- "filters": [
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "location__value",
- "kind": "String",
- "description": null
- }
]
},
{
@@ -126,52 +114,13 @@
"inherited": false,
"cardinality": "many",
"branch": "aware",
- "optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- }
- ]
+ "optional": true
}
],
"label": null,
"inherit_from": [],
"branch": "aware",
- "default_filter": "name__value",
- "filters": [
- {
- "name": "ids",
- "kind": "List",
- "description": null
- },
- {
- "name": "query__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- }
- ]
+ "default_filter": "name__value"
},
{
"name": "Repository",
@@ -255,24 +204,7 @@
"inherited": false,
"cardinality": "many",
"branch": "aware",
- "optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- }
- ]
+ "optional": true
},
{
"name": "queries",
@@ -283,29 +215,7 @@
"inherited": false,
"cardinality": "many",
"branch": "aware",
- "optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "String",
- "description": null
- },
- {
- "name": "query__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- }
- ]
+ "optional": true
},
{
"name": "credential",
@@ -323,54 +233,7 @@
"CoreGenericRepository"
],
"branch": "aware",
- "default_filter": "name__value",
- "filters": [
- {
- "name": "ids",
- "kind": "List",
- "description": null
- },
- {
- "name": "username__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "type__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "location__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "password__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "String",
- "description": null
- }
- ]
+ "default_filter": "name__value"
},
{
"name": "PasswordCredential",
@@ -400,13 +263,6 @@
"branch": "aware",
"optional": false
}
- ],
- "filters": [
- {
- "name": "ids",
- "kind": "List",
- "description": null
- }
]
},
{
@@ -441,24 +297,7 @@
"label": null,
"inherit_from": [],
"branch": "aware",
- "default_filter": "name__value",
- "filters": [
- {
- "name": "ids",
- "kind": "List",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- }
- ]
+ "default_filter": "name__value"
},
{
"name": "Location",
diff --git a/backend/tests/fixtures/schemas/schema_01.json b/backend/tests/fixtures/schemas/schema_01.json
index d92529600c..51e76c112a 100644
--- a/backend/tests/fixtures/schemas/schema_01.json
+++ b/backend/tests/fixtures/schemas/schema_01.json
@@ -49,52 +49,13 @@
"inherited": false,
"cardinality": "many",
"branch": "aware",
- "optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- }
- ]
+ "optional": true
}
],
"label": null,
"inherit_from": [],
"branch": "aware",
- "default_filter": "name__value",
- "filters": [
- {
- "name": "ids",
- "kind": "List",
- "description": null
- },
- {
- "name": "query__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- }
- ]
+ "default_filter": "name__value"
},
{
"name": "Repository",
@@ -211,24 +172,7 @@
"inherited": false,
"cardinality": "many",
"branch": "aware",
- "optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- }
- ]
+ "optional": true
},
{
"name": "queries",
@@ -239,29 +183,7 @@
"inherited": false,
"cardinality": "many",
"branch": "aware",
- "optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "String",
- "description": null
- },
- {
- "name": "query__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- }
- ]
+ "optional": true
}
],
"label": null,
@@ -270,54 +192,7 @@
"DataSource"
],
"branch": "aware",
- "default_filter": "name__value",
- "filters": [
- {
- "name": "ids",
- "kind": "List",
- "description": null
- },
- {
- "name": "username__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "type__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "location__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "password__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "String",
- "description": null
- }
- ]
+ "default_filter": "name__value"
},
{
"name": "Tag",
@@ -351,24 +226,7 @@
"label": null,
"inherit_from": [],
"branch": "aware",
- "default_filter": "name__value",
- "filters": [
- {
- "name": "ids",
- "kind": "List",
- "description": null
- },
- {
- "name": "name__value",
- "kind": "String",
- "description": null
- },
- {
- "name": "description__value",
- "kind": "String",
- "description": null
- }
- ]
+ "default_filter": "name__value"
},
{
"name": "Location",
diff --git a/backend/tests/fixtures/schemas/schema_02.json b/backend/tests/fixtures/schemas/schema_02.json
index 28ddde01eb..e75017a00a 100644
--- a/backend/tests/fixtures/schemas/schema_02.json
+++ b/backend/tests/fixtures/schemas/schema_02.json
@@ -77,15 +77,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -99,15 +90,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
}
],
@@ -116,36 +98,6 @@
"CoreGroup"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "CoreStandardGroup"
},
{
@@ -241,15 +193,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -263,15 +206,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -285,15 +219,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
}
],
@@ -302,36 +227,6 @@
"CoreGroup"
],
"branch": "local",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "CoreGraphQLQueryGroup"
},
{
@@ -423,29 +318,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "height__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -459,36 +331,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -502,36 +344,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
}
],
@@ -540,43 +352,6 @@
"TestCar"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "nbr_engine__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "nbr_seats__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "color__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "TestElectricCar"
},
{
@@ -668,29 +443,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "height__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -704,36 +456,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -747,36 +469,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
}
],
@@ -785,43 +477,6 @@
"TestCar"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "mpg__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "nbr_seats__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "color__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "TestGazCar"
},
{
@@ -881,36 +536,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "nbr_seats__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "color__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -924,36 +549,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -967,65 +562,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
}
],
"label": null,
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "height__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "TestPerson"
},
{
@@ -1115,36 +657,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -1158,83 +670,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
}
],
"label": "Criticality",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "level__value",
- "kind": "Number",
- "enum": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "BuiltinCriticality"
},
{
@@ -1296,36 +737,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -1339,65 +750,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
}
],
"label": "Tag",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "BuiltinTag"
},
{
@@ -1476,29 +834,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -1512,36 +847,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -1555,79 +860,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
}
],
"label": "Organization",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "CoreOrganization"
},
{
@@ -1766,29 +1004,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "token__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -1802,36 +1017,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -1845,36 +1030,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
}
],
@@ -1884,59 +1039,6 @@
"LineageSource"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"kind": "CoreAccount"
},
{
@@ -2013,59 +1115,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -2079,36 +1128,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -2122,65 +1141,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
}
],
"label": "Account Token",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "token__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "InternalAccountToken"
},
{
@@ -2221,59 +1187,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 2000
},
{
@@ -2287,36 +1200,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -2330,51 +1213,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
}
],
"label": "Refresh Token",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "InternalRefreshToken"
},
{
@@ -2451,59 +1295,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -2517,59 +1308,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -2583,59 +1321,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -2649,15 +1334,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -2671,22 +1347,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "resolved__value",
- "kind": "Boolean",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
},
{
@@ -2700,36 +1360,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
},
{
@@ -2743,103 +1373,29 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 10000
}
],
"label": "Proposed Change",
"inherit_from": [],
"branch": "aware",
- "filters": [
+ "kind": "CoreProposedChange"
+ },
+ {
+ "name": "ChangeThread",
+ "namespace": "Core",
+ "description": "A thread on proposed change",
+ "default_filter": null,
+ "order_by": null,
+ "display_labels": null,
+ "attributes": [
{
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "source_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "destination_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "approved_by__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreAccount",
- "description": null
- },
- {
- "name": "reviewers__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreAccount",
- "description": null
- }
- ],
- "kind": "CoreProposedChange"
- },
- {
- "name": "ChangeThread",
- "namespace": "Core",
- "description": "A thread on proposed change",
- "default_filter": null,
- "order_by": null,
- "display_labels": null,
- "attributes": [
- {
- "name": "resolved",
- "kind": "Boolean",
- "namespace": "Attribute",
- "label": null,
- "description": null,
- "default_value": false,
+ "name": "resolved",
+ "kind": "Boolean",
+ "namespace": "Attribute",
+ "label": null,
+ "description": null,
+ "default_value": false,
"enum": null,
"regex": null,
"max_length": null,
@@ -2880,36 +1436,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "source_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "destination_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -2923,15 +1449,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -2945,59 +1462,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -3011,36 +1475,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -3054,36 +1488,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
}
],
@@ -3092,29 +1496,6 @@
"CoreThread"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "resolved__value",
- "kind": "Boolean",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "change__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreProposedChange",
- "description": null
- }
- ],
"kind": "CoreChangeThread"
},
{
@@ -3223,64 +1604,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "location__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "username__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "password__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -3294,36 +1617,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "source_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "destination_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -3337,15 +1630,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
},
{
@@ -3359,59 +1643,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
},
{
@@ -3425,36 +1656,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 10000
},
{
@@ -3468,36 +1669,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 11000
}
],
@@ -3506,50 +1677,6 @@
"CoreThread"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "file__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "line_number__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "resolved__value",
- "kind": "Boolean",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "change__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreProposedChange",
- "description": null
- }
- ],
"kind": "CoreFileThread"
},
{
@@ -3624,36 +1751,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "source_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "destination_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -3667,15 +1764,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -3689,59 +1777,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -3755,36 +1790,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -3798,36 +1803,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
}
],
@@ -3836,36 +1811,6 @@
"CoreThread"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "object_path__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "resolved__value",
- "kind": "Boolean",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "change__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreProposedChange",
- "description": null
- }
- ],
"kind": "CoreObjectThread"
},
{
@@ -3925,36 +1870,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "source_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "destination_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -3968,59 +1883,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -4034,36 +1896,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -4077,36 +1909,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
}
],
@@ -4115,22 +1917,6 @@
"CoreComment"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "change__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreProposedChange",
- "description": null
- }
- ],
"kind": "CoreChangeComment"
},
{
@@ -4190,22 +1976,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "resolved__value",
- "kind": "Boolean",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -4219,59 +1989,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -4285,36 +2002,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -4328,36 +2015,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
}
],
@@ -4366,22 +2023,6 @@
"CoreComment"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "thread__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreThread",
- "description": null
- }
- ],
"kind": "CoreThreadComment"
},
{
@@ -4460,36 +2101,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -4503,72 +2114,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
}
],
"label": "Status",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "BuiltinStatus"
},
{
@@ -4647,36 +2198,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -4690,72 +2211,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
}
],
"label": "Role",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"kind": "BuiltinRole"
},
{
@@ -4834,29 +2295,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -4870,36 +2308,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -4913,79 +2321,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
}
],
"label": "Location",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "InfraSite"
},
{
@@ -5132,59 +2473,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": [
- "User",
- "Script",
- "Bot",
- "Git"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "role__value",
- "kind": "Text",
- "enum": [
- "admin",
- "read-only",
- "read-write"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
},
{
@@ -5198,29 +2486,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
},
{
@@ -5234,50 +2499,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "template_path__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "timeout__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 10000
},
{
@@ -5291,29 +2512,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 11000
},
{
@@ -5327,50 +2525,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "file_path__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "class_name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "timeout__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 12000
},
{
@@ -5384,64 +2538,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "file_path__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "class_name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "url__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "timeout__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 13000
},
{
@@ -5455,36 +2551,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 3000
},
{
@@ -5498,36 +2564,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
}
],
@@ -5537,78 +2573,6 @@
"LineageSource"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "location__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "username__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "password__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "account__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreAccount",
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "CoreRepository"
},
{
@@ -5721,64 +2685,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "location__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "username__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "password__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -5792,29 +2698,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
},
{
@@ -5828,29 +2711,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
},
{
@@ -5864,36 +2724,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 10000
},
{
@@ -5907,36 +2737,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 11000
}
],
@@ -5945,71 +2745,6 @@
"CoreTransformation"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "template_path__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "timeout__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "repository__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreRepository",
- "description": null
- },
- {
- "name": "query__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreGraphQLQuery",
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "CoreTransformJinja2"
},
{
@@ -6127,64 +2862,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "location__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "username__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "password__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -6198,29 +2875,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
},
{
@@ -6234,29 +2888,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
},
{
@@ -6270,36 +2901,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 10000
},
{
@@ -6313,107 +2914,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 11000
}
],
"label": "Check Definition",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "file_path__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "class_name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "timeout__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "repository__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreRepository",
- "description": null
- },
- {
- "name": "query__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreGraphQLQuery",
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "CoreCheckDefinition"
},
{
@@ -6560,64 +3066,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "location__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "username__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "password__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
},
{
@@ -6631,29 +3079,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 10000
},
{
@@ -6667,29 +3092,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 11000
},
{
@@ -6703,36 +3105,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 12000
},
{
@@ -6746,36 +3118,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 13000
}
],
@@ -6784,85 +3126,6 @@
"CoreTransformation"
],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "file_path__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "class_name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "url__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "timeout__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "repository__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreRepository",
- "description": null
- },
- {
- "name": "query__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreGraphQLQuery",
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "CoreTransformPython"
},
{
@@ -6941,64 +3204,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "location__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "default_branch__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "commit__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "username__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "password__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 4000
},
{
@@ -7012,29 +3217,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 5000
},
{
@@ -7048,36 +3230,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -7091,79 +3243,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
}
],
"label": "GraphQL Query",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "repository__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreRepository",
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "CoreGraphQLQuery"
},
{
@@ -7256,7 +3341,12 @@
"label": null,
"description": null,
"default_value": null,
- "enum": ["Error", "Ready", "Pending", "Processing"],
+ "enum": [
+ "Error",
+ "Ready",
+ "Pending",
+ "Processing"
+ ],
"regex": null,
"max_length": null,
"min_length": null,
@@ -7296,15 +3386,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -7318,46 +3399,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "artifact_name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "content_type__value",
- "kind": "Text",
- "enum": [
- "application/json",
- "text/plain"
- ],
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -7371,29 +3412,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
},
{
@@ -7407,36 +3425,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
},
{
@@ -7450,96 +3438,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 10000
}
],
"label": "Artifact",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "content_type__value",
- "kind": "Text",
- "enum": [
- "application/json",
- "text/plain"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "checksum__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "object__ids",
- "kind": "Text",
- "enum": null,
- "object_kind": "CoreNode",
- "description": null
- },
- {
- "name": "definition__ids",
- "kind": "Text",
- "enum": null,
- "object_kind": "CoreArtifactDefinition",
- "description": null
- },
- {
- "name": "tags__ids",
- "kind": "Text",
- "enum": null,
- "object_kind": "BuiltinTag",
- "description": null
- }
- ],
"kind": "CoreArtifact"
},
{
@@ -7655,36 +3559,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 6000
},
{
@@ -7698,43 +3572,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "timeout__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 7000
},
{
@@ -7748,36 +3585,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 8000
},
{
@@ -7791,96 +3598,12 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 9000
}
],
"label": "Artifact Definition",
"inherit_from": [],
"branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "artifact_name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "content_type__value",
- "kind": "Text",
- "enum": [
- "application/json",
- "text/plain"
- ],
- "object_kind": null,
- "description": null
- },
- {
- "name": "targets__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreGroup",
- "description": null
- },
- {
- "name": "transformation__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "CoreTransformation",
- "description": null
- }
- ],
"kind": "CoreArtifactDefinition"
}
],
@@ -7942,7 +3665,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 3000
},
{
@@ -7956,7 +3678,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 4000
}
],
@@ -8025,7 +3746,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 3000
},
{
@@ -8039,7 +3759,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 4000
}
],
@@ -8128,7 +3847,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [],
"order_weight": 4000
},
{
@@ -8142,7 +3860,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 5000
},
{
@@ -8156,7 +3873,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 6000
}
],
@@ -8244,7 +3960,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 4000
},
{
@@ -8258,7 +3973,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 5000
}
],
@@ -8289,7 +4003,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 1000
},
{
@@ -8303,7 +4016,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 2000
}
],
@@ -8371,7 +4083,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 3000
},
{
@@ -8385,7 +4096,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 4000
},
{
@@ -8399,7 +4109,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 5000
}
],
@@ -8470,7 +4179,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [],
"order_weight": 3000
},
{
@@ -8484,7 +4192,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 4000
},
{
@@ -8498,7 +4205,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 5000
},
{
@@ -8512,7 +4218,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 6000
},
{
@@ -8526,7 +4231,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 7000
}
],
@@ -8632,7 +4336,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [],
"order_weight": 6000
},
{
@@ -8646,7 +4349,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 7000
},
{
@@ -8660,7 +4362,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 8000
},
{
@@ -8674,7 +4375,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [],
"order_weight": 9000
}
],
@@ -8687,4 +4387,4 @@
"kind": "CoreTransformation"
}
]
-}
+}
\ No newline at end of file
diff --git a/backend/tests/helpers/graphql.py b/backend/tests/helpers/graphql.py
index fa769af2e0..805991a8ad 100644
--- a/backend/tests/helpers/graphql.py
+++ b/backend/tests/helpers/graphql.py
@@ -5,7 +5,7 @@
from graphql import ExecutionResult, graphql
from infrahub.core.branch import Branch
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.services import InfrahubServices, services
if TYPE_CHECKING:
diff --git a/backend/tests/helpers/schema/__init__.py b/backend/tests/helpers/schema/__init__.py
index 0096e224d3..fb283c5372 100644
--- a/backend/tests/helpers/schema/__init__.py
+++ b/backend/tests/helpers/schema/__init__.py
@@ -27,4 +27,4 @@ async def load_schema(db: InfrahubDatabase, schema: SchemaRoot) -> None:
await registry.schema.update_schema_branch(schema=tmp_schema, db=db, branch=default_branch_name, update_db=True)
-__all__ = ["CAR", "MANUFACTURER", "PERSON", "CAR_SCHEMA", "TICKET"]
+__all__ = ["CAR", "CAR_SCHEMA", "MANUFACTURER", "PERSON", "TICKET"]
diff --git a/backend/tests/helpers/test_app.py b/backend/tests/helpers/test_app.py
index cb6cfe66b5..c5eb28f241 100644
--- a/backend/tests/helpers/test_app.py
+++ b/backend/tests/helpers/test_app.py
@@ -12,13 +12,17 @@
create_default_branch,
create_global_branch,
create_root_node,
+ create_super_administrator_role,
+ create_super_administrators_group,
initialization,
)
from infrahub.core.schema import SchemaRoot, core_models, internal_schema
-from infrahub.core.schema_manager import SchemaBranch, SchemaManager
+from infrahub.core.schema.manager import SchemaManager
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.utils import delete_all_nodes
from infrahub.database import InfrahubDatabase
from infrahub.server import app, app_initialization
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
from tests.adapters.message_bus import BusSimulator
from .test_client import InfrahubTestClient
@@ -60,6 +64,14 @@ def bus_simulator(self, db: InfrahubDatabase) -> Generator[BusSimulator, None, N
yield bus
config.OVERRIDE.message_bus = original
+ @pytest.fixture(scope="class", autouse=True)
+ def workflow_local(self) -> Generator[WorkflowLocalExecution, None, None]:
+ original = config.OVERRIDE.workflow
+ workflow = WorkflowLocalExecution()
+ config.OVERRIDE.workflow = workflow
+ yield workflow
+ config.OVERRIDE.workflow = original
+
@pytest.fixture(scope="class")
async def register_internal_schema(self, db: InfrahubDatabase, default_branch: Branch) -> SchemaBranch:
schema = SchemaRoot(**internal_schema)
@@ -80,8 +92,7 @@ async def register_core_schema(
@pytest.fixture(scope="class")
async def test_client(
- self,
- initialize_registry: None,
+ self, initialize_registry: None, redis: dict[int, int] | None, nats: dict[int, int] | None
) -> InfrahubTestClient:
await app_initialization(app)
return InfrahubTestClient(app=app)
@@ -104,11 +115,10 @@ async def client(
async def initialize_registry(
self, db: InfrahubDatabase, register_core_schema: SchemaBranch, bus_simulator: BusSimulator, api_token: str
) -> None:
- await create_account(
- db=db,
- name="admin",
- password=config.SETTINGS.initial.admin_password,
- token_value=api_token,
+ admin_account = await create_account(
+ db=db, name="admin", password=config.SETTINGS.initial.admin_password, token_value=api_token
)
+ administrator_role = await create_super_administrator_role(db=db)
+ await create_super_administrators_group(db=db, role=administrator_role, admin_accounts=[admin_account])
await initialization(db=db)
diff --git a/backend/tests/helpers/test_client.py b/backend/tests/helpers/test_client.py
index 45698538ed..c3333dc053 100644
--- a/backend/tests/helpers/test_client.py
+++ b/backend/tests/helpers/test_client.py
@@ -15,7 +15,7 @@ async def dummy_async_request(
class InfrahubTestClient(httpx.AsyncClient):
- def __init__(self, app: FastAPI, base_url: str = ""):
+ def __init__(self, app: FastAPI, base_url: str = "") -> None:
self.loop = asyncio.get_event_loop()
super().__init__(app=app, base_url=base_url)
diff --git a/backend/tests/integration/conftest.py b/backend/tests/integration/conftest.py
index b7dec10a9e..e1d836450a 100644
--- a/backend/tests/integration/conftest.py
+++ b/backend/tests/integration/conftest.py
@@ -1,12 +1,14 @@
import asyncio
import os
from pathlib import Path
-from typing import Any, AsyncGenerator, Optional
+from typing import Any, Optional
import pytest
import yaml
from infrahub_sdk import UUIDT
+from prefect.testing.utilities import prefect_test_harness
+from infrahub import config
from infrahub.core import registry
from infrahub.core.constants import InfrahubKind
from infrahub.core.initialization import first_time_initialization, initialization
@@ -14,8 +16,9 @@
from infrahub.core.node import Node
from infrahub.core.schema import SchemaRoot
from infrahub.core.utils import delete_all_nodes
-from infrahub.database import InfrahubDatabase, get_db
+from infrahub.database import InfrahubDatabase
from infrahub.utils import get_models_dir
+from tests.helpers.file_repo import FileRepo
@pytest.fixture(scope="session", autouse=True)
@@ -23,6 +26,12 @@ def add_tracker():
os.environ["PYTEST_RUNNING"] = "true"
+@pytest.fixture(autouse=True, scope="session")
+def prefect_test_fixture():
+ with prefect_test_harness():
+ yield
+
+
@pytest.fixture(scope="session")
def event_loop():
"""Overrides pytest default function scoped event loop"""
@@ -32,15 +41,6 @@ def event_loop():
loop.close()
-@pytest.fixture(scope="module")
-async def db() -> AsyncGenerator[InfrahubDatabase, None]:
- driver = InfrahubDatabase(driver=await get_db(retry=1))
-
- yield driver
-
- await driver.close()
-
-
async def load_infrastructure_schema(db: InfrahubDatabase):
base_dir = get_models_dir() / "base"
@@ -89,18 +89,11 @@ async def create_token(self, account_name: Optional[str] = None) -> str:
token = str(UUIDT())
account_name = account_name or "admin"
response = await NodeManager.query(
- schema=InfrahubKind.ACCOUNT,
- db=self.db,
- filters={"name__value": account_name},
- limit=1,
+ schema=InfrahubKind.ACCOUNT, db=self.db, filters={"name__value": account_name}, limit=1
)
account = response[0]
account_token = await Node.init(db=self.db, schema=InfrahubKind.ACCOUNTTOKEN)
- await account_token.new(
- db=self.db,
- token=token,
- account=account,
- )
+ await account_token.new(db=self.db, token=token, account=account)
await account_token.save(db=self.db)
return token
@@ -108,3 +101,35 @@ async def create_token(self, account_name: Optional[str] = None) -> str:
@pytest.fixture(scope="class")
def integration_helper(db: InfrahubDatabase) -> IntegrationHelper:
return IntegrationHelper(db=db)
+
+
+@pytest.fixture
+def git_sources_dir(tmp_path: Path) -> Path:
+ source_dir = tmp_path / "sources"
+ source_dir.mkdir()
+
+ return source_dir
+
+
+@pytest.fixture
+def git_repos_dir(tmp_path: Path) -> Path:
+ repos_dir = tmp_path / "repositories"
+ repos_dir.mkdir()
+
+ config.SETTINGS.git.repositories_directory = str(repos_dir)
+
+ return repos_dir
+
+
+@pytest.fixture
+def git_repo_infrahub_demo_edge(git_sources_dir: Path) -> FileRepo:
+ """Git Repository used as part of the demo-edge tutorial."""
+
+ return FileRepo(name="infrahub-demo-edge", sources_directory=git_sources_dir)
+
+
+@pytest.fixture
+def git_repo_car_dealership(git_sources_dir: Path) -> FileRepo:
+ """Simple Git Repository used for testing."""
+
+ return FileRepo(name="car-dealership", sources_directory=git_sources_dir)
diff --git a/backend/tests/integration/git/conftest.py b/backend/tests/integration/git/conftest.py
deleted file mode 100644
index 8716a2b423..0000000000
--- a/backend/tests/integration/git/conftest.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from pathlib import Path
-
-import pytest
-
-from infrahub import config
-from tests.helpers.file_repo import FileRepo
-
-
-@pytest.fixture
-def git_sources_dir(tmp_path: Path) -> Path:
- source_dir = tmp_path / "sources"
- source_dir.mkdir()
-
- return source_dir
-
-
-@pytest.fixture
-def git_repos_dir(tmp_path: Path) -> Path:
- repos_dir = tmp_path / "repositories"
- repos_dir.mkdir()
-
- config.SETTINGS.git.repositories_directory = str(repos_dir)
-
- return repos_dir
-
-
-@pytest.fixture
-def git_repo_infrahub_demo_edge(git_sources_dir: Path) -> FileRepo:
- """Git Repository used as part of the demo-edge tutorial."""
-
- return FileRepo(name="infrahub-demo-edge", sources_directory=git_sources_dir)
diff --git a/backend/tests/integration/git/test_git_repository.py b/backend/tests/integration/git/test_git_repository.py
index a12478ffe3..1379107049 100644
--- a/backend/tests/integration/git/test_git_repository.py
+++ b/backend/tests/integration/git/test_git_repository.py
@@ -5,6 +5,7 @@
import yaml
from infrahub_sdk import Config, InfrahubClient, NodeNotFoundError
+from infrahub import config
from infrahub.core import registry
from infrahub.core.constants import InfrahubKind
from infrahub.core.initialization import first_time_initialization, initialization
@@ -14,6 +15,7 @@
from infrahub.database import InfrahubDatabase
from infrahub.git import InfrahubRepository
from infrahub.server import app, app_initialization
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
from infrahub.utils import get_models_dir
from tests.adapters.log import FakeTaskReportLogger
from tests.helpers.file_repo import FileRepo
@@ -43,7 +45,15 @@ async def load_infrastructure_schema(db: InfrahubDatabase):
class TestInfrahubClient:
@pytest.fixture(scope="class")
- async def base_dataset(self, db: InfrahubDatabase):
+ def workflow_local(prefect_test_fixture):
+ original = config.OVERRIDE.workflow
+ workflow = WorkflowLocalExecution()
+ config.OVERRIDE.workflow = workflow
+ yield workflow
+ config.OVERRIDE.workflow = original
+
+ @pytest.fixture(scope="class")
+ async def base_dataset(self, db: InfrahubDatabase, redis, nats):
await delete_all_nodes(db=db)
await first_time_initialization(db=db)
await load_infrastructure_schema(db=db)
@@ -53,6 +63,7 @@ async def base_dataset(self, db: InfrahubDatabase):
async def test_client(
self,
base_dataset,
+ workflow_local,
) -> InfrahubTestClient:
await app_initialization(app)
return InfrahubTestClient(app=app)
diff --git a/backend/tests/integration/ipam/conftest.py b/backend/tests/integration/ipam/conftest.py
index 39fef23397..d1d834d166 100644
--- a/backend/tests/integration/ipam/conftest.py
+++ b/backend/tests/integration/ipam/conftest.py
@@ -6,7 +6,7 @@
from infrahub.core.branch import Branch
from infrahub.core.constants import BranchSupportType, InfrahubKind
from infrahub.core.schema import SchemaRoot
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
@pytest.fixture(scope="class")
diff --git a/backend/tests/integration/ipam/test_ipam_utilization.py b/backend/tests/integration/ipam/test_ipam_utilization.py
index 0bdc68a057..742f628311 100644
--- a/backend/tests/integration/ipam/test_ipam_utilization.py
+++ b/backend/tests/integration/ipam/test_ipam_utilization.py
@@ -10,7 +10,7 @@
from infrahub.core.ipam.utilization import PrefixUtilizationGetter
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from tests.helpers.test_app import TestInfrahubApp
if TYPE_CHECKING:
diff --git a/backend/tests/integration/message_bus/operations/request/test_proposed_change.py b/backend/tests/integration/message_bus/operations/request/test_proposed_change.py
index 7ed4f85ecf..05e66a2a91 100644
--- a/backend/tests/integration/message_bus/operations/request/test_proposed_change.py
+++ b/backend/tests/integration/message_bus/operations/request/test_proposed_change.py
@@ -63,7 +63,7 @@
@pytest.fixture(scope="module")
-async def test_client(init_db_base) -> AsyncGenerator[InfrahubTestClient, None]:
+async def test_client(init_db_base, redis, nats) -> AsyncGenerator[InfrahubTestClient, None]:
await app_initialization(app)
async with InfrahubTestClient(app=app, base_url="http://test") as client:
yield client
diff --git a/backend/tests/integration/profiles/test_profile_lifecycle.py b/backend/tests/integration/profiles/test_profile_lifecycle.py
index f0d86c4e6e..2dcc916f76 100644
--- a/backend/tests/integration/profiles/test_profile_lifecycle.py
+++ b/backend/tests/integration/profiles/test_profile_lifecycle.py
@@ -8,7 +8,7 @@
from infrahub.core.schema.attribute_schema import AttributeSchema
from infrahub.core.schema.node_schema import NodeSchema
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from tests.helpers.schema import load_schema
from tests.helpers.test_app import TestInfrahubApp
diff --git a/backend/tests/integration/services/adapters/message_bus/test_rabbitmq.py b/backend/tests/integration/services/adapters/message_bus/test_rabbitmq.py
index 099934bd33..95d98b9554 100644
--- a/backend/tests/integration/services/adapters/message_bus/test_rabbitmq.py
+++ b/backend/tests/integration/services/adapters/message_bus/test_rabbitmq.py
@@ -62,7 +62,7 @@ class RabbitMQManager:
@property
def base_url(self) -> str:
scheme = "https" if self.settings.tls_enabled else "http"
- port = f"1{self.settings.service_port}"
+ port = f"{self.settings.rabbitmq_http_port}"
return f"{scheme}://{self.settings.address}:{port}/api"
async def create_virtual_host(self) -> None:
@@ -136,7 +136,7 @@ async def _request(self, method: str, url: str, payload: Optional[dict] = None)
@pytest.fixture
-async def rabbitmq_api() -> RabbitMQManager:
+async def rabbitmq_api(rabbitmq) -> RabbitMQManager:
settings = deepcopy(config.SETTINGS.broker)
settings.virtualhost = "integration-tests"
manager = RabbitMQManager(settings=settings)
diff --git a/sync/examples/librenms_to_infrahub/librenms/__init__.py b/backend/tests/integration/services/adapters/workflow/__init__.py
similarity index 100%
rename from sync/examples/librenms_to_infrahub/librenms/__init__.py
rename to backend/tests/integration/services/adapters/workflow/__init__.py
diff --git a/backend/tests/integration/services/adapters/workflow/conftest.py b/backend/tests/integration/services/adapters/workflow/conftest.py
new file mode 100644
index 0000000000..abcbc230ce
--- /dev/null
+++ b/backend/tests/integration/services/adapters/workflow/conftest.py
@@ -0,0 +1,17 @@
+from typing import AsyncGenerator
+
+import pytest
+from prefect.client.orchestration import PrefectClient, get_client
+
+from infrahub.workflows.initialization import setup_task_manager
+
+
+@pytest.fixture
+async def prefect_server(redis, prefect):
+ await setup_task_manager()
+
+
+@pytest.fixture
+async def prefect_client(prefect) -> AsyncGenerator[PrefectClient, None]:
+ async with get_client(sync_client=False) as client:
+ yield client
diff --git a/backend/tests/integration/services/adapters/workflow/test_prefect.py b/backend/tests/integration/services/adapters/workflow/test_prefect.py
new file mode 100644
index 0000000000..e4524ae59b
--- /dev/null
+++ b/backend/tests/integration/services/adapters/workflow/test_prefect.py
@@ -0,0 +1,19 @@
+from prefect.client.orchestration import get_client
+
+from infrahub.workflows.catalogue import INFRAHUB_WORKER_POOL
+from infrahub.workflows.initialization import setup_task_manager
+
+
+async def test_setup_task_manager(redis, prefect):
+ await setup_task_manager()
+
+ async with get_client(sync_client=False) as client:
+ response = await client.read_work_pool(INFRAHUB_WORKER_POOL.name)
+ assert response.type == INFRAHUB_WORKER_POOL.worker_type
+
+ # Setup the task manager a second time to validate that it's idempotent
+ await setup_task_manager()
+
+ async with get_client(sync_client=False) as client:
+ response = await client.read_work_pool(INFRAHUB_WORKER_POOL.name)
+ assert response.type == INFRAHUB_WORKER_POOL.worker_type
diff --git a/sync/examples/nautobot-v1_to_infrahub/infrahub/__init__.py b/backend/tests/integration/transform/__init__.py
similarity index 100%
rename from sync/examples/nautobot-v1_to_infrahub/infrahub/__init__.py
rename to backend/tests/integration/transform/__init__.py
diff --git a/backend/tests/integration/transform/test_transform_jinja2.py b/backend/tests/integration/transform/test_transform_jinja2.py
new file mode 100644
index 0000000000..4eb53d2da0
--- /dev/null
+++ b/backend/tests/integration/transform/test_transform_jinja2.py
@@ -0,0 +1,130 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import pytest
+from infrahub_sdk import Config, InfrahubClient
+
+from infrahub.core.constants import InfrahubKind
+from infrahub.core.initialization import first_time_initialization, initialization
+from infrahub.core.manager import NodeManager
+from infrahub.core.node import Node
+from infrahub.core.utils import delete_all_nodes
+from infrahub.database import InfrahubDatabase
+from infrahub.git import InfrahubRepository
+from infrahub.server import app, app_initialization
+from tests.adapters.log import FakeTaskReportLogger
+from tests.constants import TestKind
+from tests.helpers.schema import CAR_SCHEMA, load_schema
+from tests.helpers.test_app import TestInfrahubApp
+from tests.helpers.test_client import InfrahubTestClient
+
+if TYPE_CHECKING:
+ from infrahub.database import InfrahubDatabase
+ from tests.helpers.file_repo import FileRepo
+
+
+class TestCreateRepository(TestInfrahubApp):
+ @pytest.fixture(scope="class")
+ async def base_dataset(self, db: InfrahubDatabase):
+ await delete_all_nodes(db=db)
+ await first_time_initialization(db=db)
+ await load_schema(db, schema=CAR_SCHEMA)
+
+ await initialization(db=db)
+
+ john = await Node.init(schema=TestKind.PERSON, db=db)
+ await john.new(db=db, name="John", height=175, age=25)
+ await john.save(db=db)
+
+ people = await Node.init(schema=InfrahubKind.STANDARDGROUP, db=db)
+ await people.new(db=db, name="people", members=[john])
+ await people.save(db=db)
+
+ query1 = """
+ query PersonWithTheirCars($name: String!) {
+ TestingPerson(name__value: $name) {
+ edges {
+ node {
+ name {
+ value
+ }
+ age {
+ value
+ }
+ cars {
+ edges {
+ node {
+ name {
+ value
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ """
+
+ q1 = await Node.init(db=db, schema=InfrahubKind.GRAPHQLQUERY)
+ await q1.new(db=db, name="query01", query=query1)
+ await q1.save(db=db)
+
+ @pytest.fixture(scope="class")
+ async def test_client(
+ self,
+ base_dataset,
+ redis: dict[int, int] | None,
+ nats: dict[int, int] | None,
+ ) -> InfrahubTestClient:
+ await app_initialization(app)
+ return InfrahubTestClient(app=app)
+
+ @pytest.fixture
+ async def client(self, test_client: InfrahubTestClient, integration_helper): # type: ignore[override]
+ admin_token = await integration_helper.create_token()
+ config = Config(api_token=admin_token, requester=test_client.async_request)
+
+ return InfrahubClient(config=config)
+
+ @pytest.fixture
+ async def repo(self, test_client, client, db: InfrahubDatabase, git_repo_car_dealership: FileRepo, git_repos_dir):
+ # Create the repository in the Graph
+ obj = await Node.init(schema=InfrahubKind.REPOSITORY, db=db)
+ await obj.new(
+ db=db,
+ name=git_repo_car_dealership.name,
+ description="test repository",
+ location="git@github.com:mock/test.git",
+ )
+ await obj.save(db=db)
+
+ # Initialize the repository on the file system
+ repo = await InfrahubRepository.new(
+ id=obj.id,
+ name=git_repo_car_dealership.name,
+ location=git_repo_car_dealership.path,
+ task_report=FakeTaskReportLogger(),
+ client=client,
+ )
+
+ return repo
+
+ async def test_transform_jinja(self, db: InfrahubDatabase, client: InfrahubClient, repo: InfrahubRepository):
+ repositories = await NodeManager.query(db=db, schema=InfrahubKind.REPOSITORY)
+ queries = await NodeManager.query(db=db, schema=InfrahubKind.GRAPHQLQUERY)
+
+ t1 = await Node.init(db=db, schema=InfrahubKind.TRANSFORMJINJA2)
+ await t1.new(
+ db=db,
+ name="test-rfile",
+ query=str(queries[0].id),
+ repository=str(repositories[0].id),
+ template_path="templates/person_with_cars.j2",
+ )
+ await t1.save(db=db)
+
+ response = await client._get(url=f"{client.address}/api/transform/jinja2/test-rfile?name=John")
+
+ assert response.text == "Name: John"
diff --git a/backend/tests/integration/user_workflows/test_user_worflow.py b/backend/tests/integration/user_workflows/test_user_worflow.py
index b39ec38e18..9665871b5a 100644
--- a/backend/tests/integration/user_workflows/test_user_worflow.py
+++ b/backend/tests/integration/user_workflows/test_user_worflow.py
@@ -142,7 +142,7 @@ def __init__(self) -> None:
class TestUserWorkflow01:
@pytest.fixture(scope="class")
- async def client(self):
+ async def client(self, redis, nats):
client = TestClient(app)
return client
diff --git a/backend/tests/scale/common/config.py b/backend/tests/scale/common/config.py
index 6a7945e91d..963a9355cf 100644
--- a/backend/tests/scale/common/config.py
+++ b/backend/tests/scale/common/config.py
@@ -5,7 +5,7 @@ class Config(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_")
url: str = "http://localhost:8000"
api_token: str = "06438eb2-8019-4776-878c-0941b1f1d1ec"
- server_container: str = "infrahub-infrahub-server-1"
+ server_container: str = "infrahub-server-1"
db_container: str = "infrahub-database-1"
db_volume: str = "infrahub_database_data"
test_task_iterations: int = 1
diff --git a/backend/tests/scale/common/events.py b/backend/tests/scale/common/events.py
index be9a840d98..c9ddc56590 100644
--- a/backend/tests/scale/common/events.py
+++ b/backend/tests/scale/common/events.py
@@ -68,7 +68,7 @@ def request_event_handler(
"name": name,
"start_time": f"{start_time:.2f}",
"response_time": f"{response_time:.2f}ms",
- "failed": True if exception else False,
+ "failed": bool(exception),
}
if exception:
diff --git a/backend/tests/scale/common/protocols.py b/backend/tests/scale/common/protocols.py
index 665fafa8f7..e3cb7d3a8c 100644
--- a/backend/tests/scale/common/protocols.py
+++ b/backend/tests/scale/common/protocols.py
@@ -7,7 +7,7 @@
class LocustInfrahubClient(InfrahubClientSync):
"Locust protocol for Python Infrahub SDK client"
- def __init__(self, address: str, config: Config, request_event):
+ def __init__(self, address: str, config: Config, request_event) -> None:
super().__init__(address=address, config=config)
self._request_event = request_event
diff --git a/backend/tests/scale/common/users.py b/backend/tests/scale/common/users.py
index 85ad652243..df072ff5c2 100644
--- a/backend/tests/scale/common/users.py
+++ b/backend/tests/scale/common/users.py
@@ -15,7 +15,7 @@ class InfrahubClientUser(User):
delete_this_node = None
update_this_node = None
- def __init__(self, environment):
+ def __init__(self, environment) -> None:
super().__init__(environment)
self.address = environment.custom_options["config"].url
diff --git a/backend/tests/unit/api/conftest.py b/backend/tests/unit/api/conftest.py
index a9dbe6b07a..32ef935026 100644
--- a/backend/tests/unit/api/conftest.py
+++ b/backend/tests/unit/api/conftest.py
@@ -3,6 +3,7 @@
import pendulum
import pytest
from fastapi.testclient import TestClient
+from prefect.testing.utilities import prefect_test_harness
from infrahub import config
from infrahub.core.constants import InfrahubKind
@@ -10,10 +11,11 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
@pytest.fixture
-def client():
+def client(nats, redis):
# In order to mock some methods later we can't load app by default because it will automatically load all import in main.py as well
from infrahub.server import app
@@ -30,6 +32,12 @@ def admin_headers():
return {"X-INFRAHUB-KEY": "admin-security"}
+@pytest.fixture(autouse=True, scope="session")
+def prefect_test_fixture():
+ with prefect_test_harness():
+ yield
+
+
@pytest.fixture
def rpc_bus(helper):
original = config.OVERRIDE.message_bus
@@ -48,6 +56,15 @@ def rpc_bus_simulator(helper, db):
config.OVERRIDE.message_bus = original
+@pytest.fixture()
+def workflow_local():
+ original = config.OVERRIDE.workflow
+ workflow = WorkflowLocalExecution()
+ config.OVERRIDE.workflow = workflow
+ yield workflow
+ config.OVERRIDE.workflow = original
+
+
@pytest.fixture
async def car_person_data(
db: InfrahubDatabase, register_core_models_schema, car_person_schema, first_account
diff --git a/backend/tests/unit/api/test_05_query_api.py b/backend/tests/unit/api/test_05_query_api.py
index 942b949796..700ab04df8 100644
--- a/backend/tests/unit/api/test_05_query_api.py
+++ b/backend/tests/unit/api/test_05_query_api.py
@@ -1,11 +1,19 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
import pytest
-from fastapi.testclient import TestClient
-from infrahub.core.branch import Branch
from infrahub.core.initialization import create_branch
-from infrahub.database import InfrahubDatabase
from infrahub.message_bus import messages
+if TYPE_CHECKING:
+ from fastapi.testclient import TestClient
+
+ from infrahub.core.branch import Branch
+ from infrahub.core.node import Node
+ from infrahub.database import InfrahubDatabase
+
@pytest.fixture
async def base_authentication(
@@ -13,17 +21,13 @@ async def base_authentication(
default_branch: Branch,
create_test_admin,
register_core_models_schema,
-):
+) -> None:
pass
async def test_query_endpoint_group_no_params(
- db: InfrahubDatabase, client_headers, default_branch, car_person_data, patch_services
+ db: InfrahubDatabase, client: TestClient, client_headers, default_branch, car_person_data, patch_services
):
- from infrahub.server import app
-
- client = TestClient(app)
-
# Must execute in a with block to execute the startup/shutdown events
with client:
response = client.get(
@@ -61,11 +65,9 @@ async def test_query_endpoint_group_no_params(
)
-async def test_query_endpoint_group_params(db: InfrahubDatabase, client_headers, default_branch, car_person_data):
- from infrahub.server import app
-
- client = TestClient(app)
-
+async def test_query_endpoint_group_params(
+ db: InfrahubDatabase, client: TestClient, client_headers, default_branch, car_person_data
+):
# Must execute in a with block to execute the startup/shutdown events
with client:
response = client.get(
@@ -98,7 +100,7 @@ async def test_query_endpoint_group_params(db: InfrahubDatabase, client_headers,
async def test_query_endpoint_get_default_branch(
- db: InfrahubDatabase, client, client_headers, default_branch, car_person_data
+ db: InfrahubDatabase, client: TestClient, client_headers, default_branch, car_person_data
):
# Must execute in a with block to execute the startup/shutdown events
with client:
@@ -120,7 +122,7 @@ async def test_query_endpoint_get_default_branch(
async def test_query_endpoint_post_no_payload(
db: InfrahubDatabase,
- client,
+ client: TestClient,
admin_headers,
default_branch,
car_person_data,
@@ -146,7 +148,7 @@ async def test_query_endpoint_post_no_payload(
async def test_query_endpoint_post_with_params(
db: InfrahubDatabase,
- client,
+ client: TestClient,
admin_headers,
default_branch,
car_person_data,
@@ -166,7 +168,7 @@ async def test_query_endpoint_post_with_params(
async def test_query_endpoint_branch1(
- db: InfrahubDatabase, client, client_headers, default_branch, car_person_data, authentication_base
+ db: InfrahubDatabase, client: TestClient, client_headers, default_branch, car_person_data, authentication_base
):
await create_branch(branch_name="branch1", db=db)
@@ -189,7 +191,12 @@ async def test_query_endpoint_branch1(
async def test_query_endpoint_wrong_query(
- db: InfrahubDatabase, client, client_headers, default_branch, car_person_schema, register_core_models_schema
+ db: InfrahubDatabase,
+ client: TestClient,
+ client_headers,
+ default_branch,
+ car_person_schema,
+ register_core_models_schema,
):
# Must execute in a with block to execute the startup/shutdown events
with client:
@@ -202,7 +209,12 @@ async def test_query_endpoint_wrong_query(
async def test_query_endpoint_wrong_branch(
- db: InfrahubDatabase, client, client_headers, default_branch, car_person_schema, register_core_models_schema
+ db: InfrahubDatabase,
+ client: TestClient,
+ client_headers,
+ default_branch,
+ car_person_schema,
+ register_core_models_schema,
):
# Must execute in a with block to execute the startup/shutdown events
with client:
@@ -212,3 +224,29 @@ async def test_query_endpoint_wrong_branch(
)
assert response.status_code == 400
+
+
+async def test_query_endpoint_missing_privs(
+ db: InfrahubDatabase,
+ client: TestClient,
+ first_account: Node,
+ default_branch: Branch,
+ car_person_data: dict[str, Node],
+ base_authentication: None,
+) -> None:
+ with client:
+ token = client.post(
+ "/api/auth/login", json={"username": first_account.name.value, "password": first_account.password.value}
+ )
+ assert token.status_code == 200
+ access_token = token.json()["access_token"]
+
+ response = client.post(
+ "/api/query/query01",
+ headers={"Authorization": f"Bearer {access_token}"},
+ )
+
+ assert response.status_code == 403
+ error = response.json()
+ assert error["errors"]
+ assert "You do not have the following permission" in error["errors"][0]["message"]
diff --git a/backend/tests/unit/api/test_10_transformation_api.py b/backend/tests/unit/api/test_10_transformation_api.py
index d4edb6790e..94b549796f 100644
--- a/backend/tests/unit/api/test_10_transformation_api.py
+++ b/backend/tests/unit/api/test_10_transformation_api.py
@@ -1,20 +1,13 @@
-from fastapi.testclient import TestClient
-
from infrahub.core.constants import InfrahubKind
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.message_bus.messages.transform_jinja_template import TransformJinjaTemplateResponse
from infrahub.message_bus.messages.transform_python_data import TransformPythonDataResponse
async def test_transform_endpoint(
- db: InfrahubDatabase, client_headers, default_branch, rpc_bus, register_core_models_schema, car_person_data
+ db: InfrahubDatabase, client, client_headers, default_branch, rpc_bus, register_core_models_schema, car_person_data
):
- from infrahub.server import app
-
- client = TestClient(app)
-
repositories = await NodeManager.query(db=db, schema=InfrahubKind.REPOSITORY)
queries = await NodeManager.query(db=db, schema=InfrahubKind.GRAPHQLQUERY)
@@ -46,39 +39,3 @@ async def test_transform_endpoint(
result = response.json()
assert result == {"KEY1": "value1", "KEY2": "value2"}
-
-
-async def test_rfile_endpoint(
- db: InfrahubDatabase, client_headers, default_branch, rpc_bus, register_core_models_schema, car_person_data
-):
- from infrahub.server import app
-
- client = TestClient(app)
-
- repositories = await NodeManager.query(db=db, schema=InfrahubKind.REPOSITORY)
- queries = await NodeManager.query(db=db, schema=InfrahubKind.GRAPHQLQUERY)
-
- t1 = await Node.init(db=db, schema=InfrahubKind.TRANSFORMJINJA2)
- await t1.new(
- db=db,
- name="test-rfile",
- query=str(queries[0].id),
- repository=str(repositories[0].id),
- template_path="templates/device_startup_config.tpl.j2",
- )
- await t1.save(db=db)
-
- # Must execute in a with block to execute the startup/shutdown events
- with client:
- mock_response = TransformJinjaTemplateResponse(
- data={"rendered_template": "Rendered by a mocked agent"},
- )
- rpc_bus.add_mock_reply(response=mock_response)
-
- response = client.get(
- "/api/transform/jinja2/test-rfile",
- headers=client_headers,
- )
-
- assert response.status_code == 200
- assert response.text == "Rendered by a mocked agent"
diff --git a/backend/tests/unit/api/test_11_artifact.py b/backend/tests/unit/api/test_11_artifact.py
index f6d2104788..b982c5dc53 100644
--- a/backend/tests/unit/api/test_11_artifact.py
+++ b/backend/tests/unit/api/test_11_artifact.py
@@ -1,5 +1,3 @@
-from fastapi.testclient import TestClient
-
from infrahub.core import registry
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
@@ -9,6 +7,7 @@
async def test_artifact_definition_endpoint(
db: InfrahubDatabase,
+ client,
admin_headers,
default_branch,
rpc_bus,
@@ -17,10 +16,6 @@ async def test_artifact_definition_endpoint(
car_person_data_generic,
authentication_base,
):
- from infrahub.server import app
-
- client = TestClient(app)
-
g1 = await Node.init(db=db, schema=InfrahubKind.STANDARDGROUP)
await g1.new(db=db, name="group1", members=[car_person_data_generic["c1"], car_person_data_generic["c2"]])
await g1.save(db=db)
@@ -64,16 +59,13 @@ async def test_artifact_definition_endpoint(
async def test_artifact_endpoint(
db: InfrahubDatabase,
+ client,
admin_headers,
register_core_models_schema,
register_builtin_models_schema,
car_person_data_generic,
authentication_base,
):
- from infrahub.server import app
-
- client = TestClient(app)
-
with client:
response = client.get("/api/artifact/95008984-16ca-4e58-8323-0899bb60035f", headers=admin_headers)
assert response.status_code == 404
diff --git a/backend/tests/unit/api/test_12_file.py b/backend/tests/unit/api/test_12_file.py
index 1bf3c1d048..3a4a966e46 100644
--- a/backend/tests/unit/api/test_12_file.py
+++ b/backend/tests/unit/api/test_12_file.py
@@ -1,5 +1,3 @@
-from fastapi.testclient import TestClient
-
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
@@ -8,15 +6,12 @@
async def test_get_file(
db: InfrahubDatabase,
+ client,
client_headers,
default_branch,
rpc_bus,
register_core_models_schema,
):
- from infrahub.server import app
-
- client = TestClient(app)
-
r1 = await Node.init(db=db, schema=InfrahubKind.REPOSITORY)
await r1.new(db=db, name="repo01", location="git@github.com:user/repo01.git")
await r1.save(db=db)
diff --git a/backend/tests/unit/api/test_20_graphql_api.py b/backend/tests/unit/api/test_20_graphql_api.py
index 17ded28d46..2239ed6f93 100644
--- a/backend/tests/unit/api/test_20_graphql_api.py
+++ b/backend/tests/unit/api/test_20_graphql_api.py
@@ -221,7 +221,14 @@ async def test_download_schema(db: InfrahubDatabase, client, client_headers):
async def test_query_at_previous_schema(
- db: InfrahubDatabase, client, admin_headers, default_branch: Branch, authentication_base, car_person_data
+ db: InfrahubDatabase,
+ client,
+ admin_headers,
+ default_branch: Branch,
+ authentication_base,
+ prefect_test_fixture,
+ workflow_local,
+ car_person_data,
):
# Load the schema in the database
schema = registry.schema.get_schema_branch(name=default_branch.name)
diff --git a/backend/tests/unit/api/test_40_schema_api.py b/backend/tests/unit/api/test_40_schema_api.py
index 3c51455024..28ececed2d 100644
--- a/backend/tests/unit/api/test_40_schema_api.py
+++ b/backend/tests/unit/api/test_40_schema_api.py
@@ -7,21 +7,16 @@
from infrahub.core.path import SchemaPath
from infrahub.core.schema import SchemaRoot, core_models
from infrahub.core.utils import count_relationships
-from infrahub.core.validators.model import SchemaViolation
from infrahub.database import InfrahubDatabase
from infrahub.message_bus.messages.schema_migration_path import (
SchemaMigrationPathResponse,
SchemaMigrationPathResponseData,
)
-from infrahub.message_bus.messages.schema_validator_path import (
- SchemaValidatorPathResponse,
- SchemaValidatorPathResponseData,
-)
async def test_schema_read_endpoint_default_branch(
db: InfrahubDatabase,
- client,
+ client: TestClient,
client_headers,
default_branch: Branch,
car_person_schema_generics: SchemaRoot,
@@ -97,7 +92,7 @@ async def test_schema_read_endpoint_wrong_branch(
async def test_schema_summary_default_branch(
db: InfrahubDatabase,
- client,
+ client: TestClient,
client_headers,
default_branch: Branch,
car_person_schema_generics: SchemaRoot,
@@ -121,7 +116,7 @@ async def test_schema_summary_default_branch(
async def test_schema_kind_default_branch(
db: InfrahubDatabase,
- client,
+ client: TestClient,
client_headers,
default_branch: Branch,
car_person_schema_generics: SchemaRoot,
@@ -140,7 +135,6 @@ async def test_schema_kind_default_branch(
assert "id" in schema
assert "hash" in schema
- assert "filters" in schema
assert "relationships" in schema
@@ -174,7 +168,7 @@ async def test_json_schema_kind_default_branch(
async def test_schema_kind_not_valid(
db: InfrahubDatabase,
- client,
+ client: TestClient,
client_headers,
default_branch: Branch,
car_person_schema_generics: SchemaRoot,
@@ -195,6 +189,8 @@ async def test_schema_load_endpoint_valid_simple(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
helper,
):
@@ -230,6 +226,8 @@ async def test_schema_load_restricted_namespace(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
helper,
):
@@ -249,6 +247,8 @@ async def test_schema_load_endpoint_idempotent_simple(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
register_core_schema_db,
authentication_base,
helper,
@@ -296,6 +296,8 @@ async def test_schema_load_endpoint_valid_with_generics(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
register_core_schema_db,
authentication_base,
helper,
@@ -325,6 +327,8 @@ async def test_schema_load_endpoint_idempotent_with_generics(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
register_core_schema_db,
authentication_base,
helper,
@@ -372,6 +376,8 @@ async def test_schema_load_endpoint_valid_with_extensions(
admin_headers,
rpc_bus,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
helper,
):
@@ -418,6 +424,8 @@ async def test_schema_load_endpoint_not_valid_simple_02(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
helper,
):
@@ -437,6 +445,8 @@ async def test_schema_load_endpoint_not_valid_simple_03(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
helper,
):
@@ -456,6 +466,8 @@ async def test_schema_load_endpoint_not_valid_simple_04(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
helper,
):
@@ -475,6 +487,8 @@ async def test_schema_load_endpoint_not_valid_simple_05(
client: TestClient,
admin_headers,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
helper,
):
@@ -517,6 +531,8 @@ async def test_schema_load_endpoint_constraints_not_valid(
admin_headers,
rpc_bus,
default_branch: Branch,
+ prefect_test_fixture,
+ workflow_local,
authentication_base,
car_person_schema,
car_accord_main,
@@ -524,32 +540,10 @@ async def test_schema_load_endpoint_constraints_not_valid(
person_john_main,
helper,
):
- # person = await Node.init(db=db, schema="TestPerson", branch=default_branch)
- # await person.new(db=db, name="ALFRED", height=160, cars=[car_accord_main.id])
- # await person.save(db=db)
-
# Load the schema in the database
schema = registry.schema.get_schema_branch(name=default_branch.name)
await registry.schema.load_schema_to_db(schema=schema, branch=default_branch, db=db)
- rpc_bus.response.append(
- SchemaValidatorPathResponse(
- data=SchemaValidatorPathResponseData(
- violations=[
- SchemaViolation(
- node_id="cf85d101-c6d6-41aa-b1ab-41bc4c7d46f1",
- node_kind="TestPerson",
- display_label="ALFRED",
- full_display_label="Alfred TestPerson(cf85d101-c6d6-41aa-b1ab-41bc4c7d46f1)",
- message="clear error message",
- )
- ],
- constraint_name="attribute.regex.update",
- schema_path=SchemaPath(path_type=SchemaPathType.ATTRIBUTE, schema_kind="TestPerson", field_name="name"),
- )
- )
- )
-
person_schema = {
"name": "Person",
"namespace": "Test",
@@ -572,8 +566,9 @@ async def test_schema_load_endpoint_constraints_not_valid(
json={"schemas": [{"version": "1.0", "nodes": [person_schema]}]},
)
+ error_message = f"Node John (TestPerson: {person_john_main.id}) is not compatible with the constraint 'attribute.regex.update' at 'schema/TestPerson/name/regex'" # noqa: E501
assert response.json() == {
"data": None,
- "errors": [{"extensions": {"code": 422}, "message": "clear error message"}],
+ "errors": [{"extensions": {"code": 422}, "message": error_message}],
}
assert response.status_code == 422
diff --git a/backend/tests/unit/api/test_50_config_api.py b/backend/tests/unit/api/test_50_config_api.py
index 139b98b16c..a1c5b3ca0b 100644
--- a/backend/tests/unit/api/test_50_config_api.py
+++ b/backend/tests/unit/api/test_50_config_api.py
@@ -13,4 +13,4 @@ async def test_config_endpoint(db: InfrahubDatabase, client, client_headers, def
config = response.json()
- assert sorted(config.keys()) == ["analytics", "experimental_features", "logging", "main"]
+ assert sorted(config.keys()) == ["analytics", "experimental_features", "logging", "main", "sso"]
diff --git a/backend/tests/unit/api/test_60_storage.py b/backend/tests/unit/api/test_60_storage.py
index 2dfc606da4..b9a7937318 100644
--- a/backend/tests/unit/api/test_60_storage.py
+++ b/backend/tests/unit/api/test_60_storage.py
@@ -9,15 +9,16 @@
async def test_file_upload(
- db: InfrahubDatabase, helper, local_storage_dir: str, admin_headers, default_branch: Branch, authentication_base
+ db: InfrahubDatabase,
+ client: TestClient,
+ helper,
+ local_storage_dir: str,
+ admin_headers,
+ default_branch: Branch,
+ authentication_base,
):
- from infrahub.server import app
-
- client = TestClient(app)
-
fixture_dir = helper.get_fixtures_dir()
- fixture_dir = helper.get_fixtures_dir()
files_dir = os.path.join(fixture_dir, "schemas")
filenames = [item.name for item in os.scandir(files_dir) if item.is_file()]
file_path = Path(os.path.join(files_dir, filenames[0]))
@@ -40,14 +41,14 @@ async def test_file_upload(
async def test_content_upload(
- db: InfrahubDatabase, helper, local_storage_dir: str, admin_headers, default_branch: Branch, authentication_base
+ db: InfrahubDatabase,
+ client: TestClient,
+ helper,
+ local_storage_dir: str,
+ admin_headers,
+ default_branch: Branch,
+ authentication_base,
):
- from infrahub.server import app
-
- client = TestClient(app)
-
- fixture_dir = helper.get_fixtures_dir()
-
fixture_dir = helper.get_fixtures_dir()
files_dir = os.path.join(fixture_dir, "schemas")
filenames = [item.name for item in os.scandir(files_dir) if item.is_file()]
diff --git a/backend/tests/unit/api/test_api_base.py b/backend/tests/unit/api/test_api_base.py
index 0b52a09638..0057268231 100644
--- a/backend/tests/unit/api/test_api_base.py
+++ b/backend/tests/unit/api/test_api_base.py
@@ -1,6 +1,4 @@
-async def test_get_invalid(
- client,
-):
+async def test_get_invalid(client, db):
with client:
response = client.get(
"/api/so-such-route",
diff --git a/backend/tests/unit/api/test_api_exception_handler.py b/backend/tests/unit/api/test_api_exception_handler.py
index d674926a7a..dee82c508f 100644
--- a/backend/tests/unit/api/test_api_exception_handler.py
+++ b/backend/tests/unit/api/test_api_exception_handler.py
@@ -26,7 +26,7 @@ class MockError(Error):
HTTP_CODE = 418
DESCRIPTION = "the teapot error"
- def __init__(self, message: Optional[str]):
+ def __init__(self, message: Optional[str]) -> None:
self.message = message or ""
diff --git a/backend/tests/unit/api/test_menu.py b/backend/tests/unit/api/test_menu.py
index d727792c1c..4d37efaf70 100644
--- a/backend/tests/unit/api/test_menu.py
+++ b/backend/tests/unit/api/test_menu.py
@@ -1,5 +1,6 @@
from infrahub.api.menu import InterfaceMenu
from infrahub.core.branch import Branch
+from infrahub.core.initialization import create_default_menu
from infrahub.core.schema import SchemaRoot
from infrahub.database import InfrahubDatabase
@@ -24,3 +25,23 @@ async def test_get_menu(
menu = [InterfaceMenu(**menu_item) for menu_item in response.json()]
assert menu[0].title == "Objects"
assert menu[0].children[0].title == "Car"
+
+
+async def test_get_new_menu(
+ db: InfrahubDatabase,
+ client,
+ client_headers,
+ default_branch: Branch,
+ car_person_schema_generics: SchemaRoot,
+ car_person_data_generic,
+):
+ await create_default_menu(db=db)
+
+ with client:
+ response = client.get(
+ "/api/menu/new",
+ headers=client_headers,
+ )
+
+ assert response.status_code == 200
+ assert response.json() is not None
diff --git a/backend/tests/unit/conftest.py b/backend/tests/unit/conftest.py
index 81d168b0b6..9b1f87ceb1 100644
--- a/backend/tests/unit/conftest.py
+++ b/backend/tests/unit/conftest.py
@@ -22,7 +22,14 @@
StringOptional,
)
from infrahub.core.branch import Branch
-from infrahub.core.constants import GLOBAL_BRANCH_NAME, BranchSupportType, InfrahubKind
+from infrahub.core.constants import (
+ GLOBAL_BRANCH_NAME,
+ BranchSupportType,
+ GlobalPermissions,
+ InfrahubKind,
+ PermissionAction,
+ PermissionDecision,
+)
from infrahub.core.initialization import (
create_branch,
create_default_branch,
@@ -42,12 +49,13 @@
SchemaRoot,
core_models,
)
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.utils import delete_all_nodes
from infrahub.database import InfrahubDatabase
from infrahub.dependencies.registry import build_component_registry
from infrahub.git import InfrahubRepository
from infrahub.test_data import dataset01 as ds01
+from infrahub.utils import format_label
from tests.helpers.file_repo import FileRepo
from tests.helpers.test_client import dummy_async_request
@@ -2454,11 +2462,16 @@ async def register_core_schema_db(db: InfrahubDatabase, default_branch: Branch,
@pytest.fixture
async def register_account_schema(db: InfrahubDatabase) -> None:
SCHEMAS_TO_REGISTER = [
+ InfrahubKind.ACCOUNTGROUP,
+ InfrahubKind.ACCOUNTROLE,
InfrahubKind.GENERICACCOUNT,
InfrahubKind.ACCOUNT,
InfrahubKind.ACCOUNTTOKEN,
InfrahubKind.GENERICGROUP,
InfrahubKind.REFRESHTOKEN,
+ InfrahubKind.BASEPERMISSION,
+ InfrahubKind.GLOBALPERMISSION,
+ InfrahubKind.OBJECTPERMISSION,
]
nodes = [item for item in core_models["nodes"] if f'{item["namespace"]}{item["name"]}' in SCHEMAS_TO_REGISTER]
generics = [item for item in core_models["generics"] if f'{item["namespace"]}{item["name"]}' in SCHEMAS_TO_REGISTER]
@@ -2522,11 +2535,47 @@ async def register_ipam_extended_schema(default_branch: Branch, register_ipam_sc
@pytest.fixture
async def create_test_admin(db: InfrahubDatabase, register_core_models_schema, data_schema) -> Node:
+ """Create a test admin account, group and role with all global permissions."""
+ permissions: list[Node] = []
+ global_permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await global_permission.new(
+ db=db,
+ name=format_label(GlobalPermissions.SUPER_ADMIN.value),
+ action=GlobalPermissions.SUPER_ADMIN.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ await global_permission.save(db=db)
+ permissions.append(global_permission)
+
+ object_permission = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
+ await object_permission.new(
+ db=db,
+ branch="*",
+ namespace="*",
+ name="*",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ await object_permission.save(db=db)
+ permissions.append(object_permission)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=permissions)
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
account = await Node.init(db=db, schema=InfrahubKind.ACCOUNT)
await account.new(
db=db, name="test-admin", account_type="User", password=config.SETTINGS.initial.admin_password, role="admin"
)
await account.save(db=db)
+
+ await group.members.add(db=db, data=account)
+ await group.members.save(db=db)
+
token = await Node.init(db=db, schema=InfrahubKind.ACCOUNTTOKEN)
await token.new(db=db, token="admin-security", account=account)
await token.save(db=db)
@@ -2560,6 +2609,12 @@ async def first_account(db: InfrahubDatabase, data_schema, node_group_schema, re
return obj
+@pytest.fixture
+async def session_first_account(db: InfrahubDatabase, first_account) -> AccountSession:
+ session = AccountSession(authenticated=True, auth_type=AuthType.API, account_id=first_account.id, role="read-write")
+ return session
+
+
@pytest.fixture
async def second_account(db: InfrahubDatabase, data_schema, node_group_schema, register_account_schema) -> Node:
obj = await Node.init(db=db, schema=InfrahubKind.ACCOUNT)
diff --git a/backend/tests/unit/core/constraint_validators/test_relationship_profiles_kind.py b/backend/tests/unit/core/constraint_validators/test_relationship_profiles_kind.py
index 9675f06fa9..75675a8309 100644
--- a/backend/tests/unit/core/constraint_validators/test_relationship_profiles_kind.py
+++ b/backend/tests/unit/core/constraint_validators/test_relationship_profiles_kind.py
@@ -6,7 +6,7 @@
from infrahub.core.node import Node
from infrahub.core.relationship.constraints.profiles_kind import RelationshipProfilesKindConstraint
from infrahub.core.schema import SchemaRoot
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
from infrahub.exceptions import ValidationError
from tests.helpers.test_app import TestInfrahubApp
diff --git a/backend/tests/unit/core/constraint_validators/test_task_schema_validate_migrations.py b/backend/tests/unit/core/constraint_validators/test_task_schema_validate_migrations.py
new file mode 100644
index 0000000000..260e349cae
--- /dev/null
+++ b/backend/tests/unit/core/constraint_validators/test_task_schema_validate_migrations.py
@@ -0,0 +1,49 @@
+from infrahub_sdk import InfrahubClient
+
+from infrahub.core import registry
+from infrahub.core.branch import Branch
+from infrahub.core.constants import SchemaPathType
+from infrahub.core.models import SchemaUpdateConstraintInfo
+from infrahub.core.node import Node
+from infrahub.core.path import SchemaPath
+from infrahub.core.validators.models.validate_migration import SchemaValidateMigrationData
+from infrahub.core.validators.tasks import schema_validate_migrations
+from infrahub.database import InfrahubDatabase
+from infrahub.services import InfrahubServices, services
+from infrahub.services.adapters.message_bus.local import BusSimulator
+from infrahub.services.adapters.workflow.local import WorkflowLocalExecution
+
+
+async def test_schema_validate_migrations(
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ prefect_test_fixture,
+ car_accord_main: Node,
+ car_volt_main: Node,
+ person_john_main,
+ helper,
+):
+ schema = registry.schema.get_schema_branch(name=default_branch.name).duplicate()
+ person_schema = schema.get(name="TestPerson")
+ name_attr = person_schema.get_attribute(name="name")
+ name_attr.regex = r"^[A-Z]+$"
+ schema.set(name="TestPerson", schema=person_schema)
+
+ constraints = [
+ SchemaUpdateConstraintInfo(
+ constraint_name="attribute.regex.update",
+ path=SchemaPath(path_type=SchemaPathType.ATTRIBUTE, schema_kind="TestPerson", field_name="name"),
+ )
+ ]
+
+ services.service = InfrahubServices(
+ message_bus=BusSimulator(database=db), client=InfrahubClient(), workflow=WorkflowLocalExecution(), database=db
+ )
+
+ message = SchemaValidateMigrationData(branch=default_branch, schema_branch=schema, constraints=constraints)
+ errors = await schema_validate_migrations(
+ message=message,
+ )
+
+ assert len(errors) == 1
+ assert "is not compatible with the constraint 'attribute.regex.update'" in errors[0]
diff --git a/backend/tests/unit/core/diff/test_diff_calculator.py b/backend/tests/unit/core/diff/test_diff_calculator.py
index a9c4a3d295..d426f62f19 100644
--- a/backend/tests/unit/core/diff/test_diff_calculator.py
+++ b/backend/tests/unit/core/diff/test_diff_calculator.py
@@ -8,7 +8,7 @@
from infrahub.core.initialization import create_branch
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.timestamp import Timestamp
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/diff/test_diff_combiner.py b/backend/tests/unit/core/diff/test_diff_combiner.py
index 70906cdb5b..2ff868215d 100644
--- a/backend/tests/unit/core/diff/test_diff_combiner.py
+++ b/backend/tests/unit/core/diff/test_diff_combiner.py
@@ -19,8 +19,8 @@
EnrichedDiffs,
EnrichedDiffSingleRelationship,
)
+from infrahub.core.schema.manager import SchemaManager
from infrahub.core.schema.node_schema import NodeSchema
-from infrahub.core.schema_manager import SchemaManager
from infrahub.core.timestamp import Timestamp
from .factories import (
diff --git a/backend/tests/unit/core/diff/test_diff_merger.py b/backend/tests/unit/core/diff/test_diff_merger.py
new file mode 100644
index 0000000000..f30e3480e3
--- /dev/null
+++ b/backend/tests/unit/core/diff/test_diff_merger.py
@@ -0,0 +1,221 @@
+from unittest.mock import AsyncMock, call
+from uuid import uuid4
+
+import pytest
+
+from infrahub.core.branch import Branch
+from infrahub.core.constants import DiffAction
+from infrahub.core.diff.merger.merger import DiffMerger
+from infrahub.core.diff.merger.serializer import DiffMergeSerializer
+from infrahub.core.diff.model.path import (
+ BranchTrackingId,
+ ConflictSelection,
+ EnrichedDiffNode,
+ EnrichedDiffRoot,
+)
+from infrahub.core.diff.repository.repository import DiffRepository
+from infrahub.core.initialization import create_branch
+from infrahub.core.manager import NodeManager
+from infrahub.core.node import Node
+from infrahub.core.timestamp import Timestamp
+from infrahub.database import InfrahubDatabase
+from infrahub.exceptions import NodeNotFoundError
+from tests.unit.core.diff.factories import EnrichedConflictFactory, EnrichedNodeFactory, EnrichedRootFactory
+
+
+class TestMergeDiff:
+ @pytest.fixture
+ async def source_branch(self, db: InfrahubDatabase, default_branch: Branch) -> Branch:
+ return await create_branch(db=db, branch_name="source")
+
+ @pytest.fixture
+ def mock_diff_repository(self) -> DiffRepository:
+ return AsyncMock(spec=DiffRepository)
+
+ @pytest.fixture
+ def diff_merger(
+ self, db: InfrahubDatabase, default_branch: Branch, source_branch: Branch, mock_diff_repository: DiffRepository
+ ) -> DiffMerger:
+ return DiffMerger(
+ db=db,
+ source_branch=source_branch,
+ destination_branch=default_branch,
+ diff_repository=mock_diff_repository,
+ serializer=DiffMergeSerializer(),
+ )
+
+ @pytest.fixture
+ async def person_node_branch(self, db: InfrahubDatabase, source_branch: Branch, car_person_schema) -> Node:
+ new_node = await Node.init(db=db, schema="TestPerson", branch=source_branch)
+ await new_node.new(db=db, name="Albert", height=172)
+ await new_node.save(db=db)
+ return new_node
+
+ @pytest.fixture
+ async def person_node_main(self, db: InfrahubDatabase, default_branch: Branch, car_person_schema) -> Node:
+ new_node = await Node.init(db=db, schema="TestPerson", branch=default_branch)
+ await new_node.new(db=db, name="Albert", height=172)
+ await new_node.save(db=db)
+ return new_node
+
+ @pytest.fixture
+ def empty_diff_root(self, default_branch: Branch, source_branch: Branch) -> EnrichedDiffRoot:
+ return EnrichedRootFactory.build(
+ base_branch_name=default_branch.name,
+ diff_branch_name=source_branch.name,
+ from_time=Timestamp(source_branch.get_created_at()),
+ to_time=Timestamp(),
+ uuid=str(uuid4()),
+ partner_uuid=str(uuid4()),
+ tracking_id=BranchTrackingId(name=source_branch.name),
+ nodes=set(),
+ )
+
+ def _get_empty_node_diff(self, node: Node, action: DiffAction) -> EnrichedDiffNode:
+ return EnrichedNodeFactory.build(
+ uuid=node.get_id(), action=action, kind=node.get_kind(), label="", attributes=set(), relationships=set()
+ )
+
+ async def test_merge_node_added(
+ self,
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ source_branch: Branch,
+ person_node_branch: Node,
+ mock_diff_repository: DiffRepository,
+ diff_merger: DiffMerger,
+ empty_diff_root: EnrichedDiffRoot,
+ ):
+ added_node_diff = self._get_empty_node_diff(node=person_node_branch, action=DiffAction.ADDED)
+ empty_diff_root.nodes = {added_node_diff}
+ mock_diff_repository.get_one.return_value = empty_diff_root
+ at = Timestamp()
+
+ await diff_merger.merge_graph(at=at)
+
+ mock_diff_repository.get_one.assert_awaited_once_with(
+ diff_branch_name=source_branch.name, tracking_id=BranchTrackingId(name=source_branch.name)
+ )
+ target_car = await NodeManager.get_one(db=db, branch=default_branch, id=person_node_branch.id)
+ assert target_car.id == person_node_branch.id
+ assert target_car.get_updated_at() == at
+
+ async def test_merge_node_added_idempotent(
+ self,
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ source_branch: Branch,
+ person_node_branch: Node,
+ mock_diff_repository: DiffRepository,
+ diff_merger: DiffMerger,
+ empty_diff_root: EnrichedDiffRoot,
+ ):
+ added_node_diff = self._get_empty_node_diff(node=person_node_branch, action=DiffAction.ADDED)
+ empty_diff_root.nodes = {added_node_diff}
+ mock_diff_repository.get_one.return_value = empty_diff_root
+ at = Timestamp()
+
+ await diff_merger.merge_graph(at=at)
+ await diff_merger.merge_graph(at=at)
+
+ assert mock_diff_repository.get_one.await_args_list == [
+ call(diff_branch_name=source_branch.name, tracking_id=BranchTrackingId(name=source_branch.name)),
+ call(diff_branch_name=source_branch.name, tracking_id=BranchTrackingId(name=source_branch.name)),
+ ]
+ target_car = await NodeManager.get_one(db=db, branch=default_branch, id=person_node_branch.id)
+ assert target_car.id == person_node_branch.id
+ assert target_car.get_updated_at() == at
+
+ async def test_merge_node_deleted(
+ self,
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ person_node_main: Node,
+ source_branch: Branch,
+ mock_diff_repository: DiffRepository,
+ diff_merger: DiffMerger,
+ empty_diff_root: EnrichedDiffRoot,
+ ):
+ person_node_branch = await NodeManager.get_one(db=db, branch=source_branch, id=person_node_main.id)
+ await person_node_branch.delete(db=db)
+ deleted_node_diff = self._get_empty_node_diff(node=person_node_branch, action=DiffAction.REMOVED)
+ empty_diff_root.nodes = {deleted_node_diff}
+ mock_diff_repository.get_one.return_value = empty_diff_root
+ at = Timestamp()
+
+ await diff_merger.merge_graph(at=at)
+
+ mock_diff_repository.get_one.assert_awaited_once_with(
+ diff_branch_name=source_branch.name, tracking_id=BranchTrackingId(name=source_branch.name)
+ )
+ with pytest.raises(NodeNotFoundError):
+ await NodeManager.get_one(db=db, branch=default_branch, id=person_node_main.id, raise_on_error=True)
+
+ async def test_merge_node_deleted_idempotent(
+ self,
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ person_node_main: Node,
+ source_branch: Branch,
+ mock_diff_repository: DiffRepository,
+ diff_merger: DiffMerger,
+ empty_diff_root: EnrichedDiffRoot,
+ ):
+ person_node_branch = await NodeManager.get_one(db=db, branch=source_branch, id=person_node_main.id)
+ await person_node_branch.delete(db=db)
+ deleted_node_diff = self._get_empty_node_diff(node=person_node_branch, action=DiffAction.REMOVED)
+ empty_diff_root.nodes = {deleted_node_diff}
+ mock_diff_repository.get_one.return_value = empty_diff_root
+ at = Timestamp()
+
+ await diff_merger.merge_graph(at=at)
+ await diff_merger.merge_graph(at=at)
+
+ assert mock_diff_repository.get_one.await_args_list == [
+ call(diff_branch_name=source_branch.name, tracking_id=BranchTrackingId(name=source_branch.name)),
+ call(diff_branch_name=source_branch.name, tracking_id=BranchTrackingId(name=source_branch.name)),
+ ]
+ with pytest.raises(NodeNotFoundError):
+ await NodeManager.get_one(db=db, branch=default_branch, id=person_node_main.id, raise_on_error=True)
+
+ @pytest.mark.parametrize(
+ "conflict_selection,expect_deleted",
+ [(ConflictSelection.DIFF_BRANCH, True), (ConflictSelection.BASE_BRANCH, False)],
+ )
+ async def test_merge_node_deleted_with_conflict(
+ self,
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ person_node_main: Node,
+ source_branch: Branch,
+ mock_diff_repository: DiffRepository,
+ diff_merger: DiffMerger,
+ empty_diff_root: EnrichedDiffRoot,
+ conflict_selection: ConflictSelection,
+ expect_deleted: bool,
+ ):
+ person_node_branch = await NodeManager.get_one(db=db, branch=source_branch, id=person_node_main.id)
+ await person_node_branch.delete(db=db)
+ deleted_node_diff = self._get_empty_node_diff(node=person_node_branch, action=DiffAction.REMOVED)
+ node_conflict = EnrichedConflictFactory.build(
+ base_branch_action=DiffAction.UPDATED,
+ diff_branch_action=DiffAction.REMOVED,
+ selected_branch=conflict_selection,
+ )
+ deleted_node_diff.conflict = node_conflict
+ empty_diff_root.nodes = {deleted_node_diff}
+ mock_diff_repository.get_one.return_value = empty_diff_root
+ at = Timestamp()
+
+ await diff_merger.merge_graph(at=at)
+
+ mock_diff_repository.get_one.assert_awaited_once_with(
+ diff_branch_name=source_branch.name, tracking_id=BranchTrackingId(name=source_branch.name)
+ )
+ if expect_deleted:
+ with pytest.raises(NodeNotFoundError):
+ await NodeManager.get_one(db=db, branch=default_branch, id=person_node_main.id, raise_on_error=True)
+ else:
+ target_car = await NodeManager.get_one(db=db, branch=default_branch, id=person_node_branch.id)
+ assert target_car.id == person_node_branch.id
+ assert target_car.get_updated_at() < at
diff --git a/backend/tests/unit/core/diff/test_diff_payload.py b/backend/tests/unit/core/diff/test_diff_payload.py
index 5d8aaf4df3..fbf70a2d35 100644
--- a/backend/tests/unit/core/diff/test_diff_payload.py
+++ b/backend/tests/unit/core/diff/test_diff_payload.py
@@ -10,7 +10,7 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.core.schema.relationship_schema import RelationshipSchema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/ipam/conftest.py b/backend/tests/unit/core/ipam/conftest.py
index 173beccebe..8daaeb0f49 100644
--- a/backend/tests/unit/core/ipam/conftest.py
+++ b/backend/tests/unit/core/ipam/conftest.py
@@ -4,7 +4,7 @@
from infrahub.core.branch import Branch
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/ipam/test_ipam.py b/backend/tests/unit/core/ipam/test_ipam.py
index 70dda42230..68c898aa72 100644
--- a/backend/tests/unit/core/ipam/test_ipam.py
+++ b/backend/tests/unit/core/ipam/test_ipam.py
@@ -12,7 +12,7 @@
IPPrefixSubnetFetch,
get_ip_addresses,
)
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/ipam/test_ipam_reconcile_query.py b/backend/tests/unit/core/ipam/test_ipam_reconcile_query.py
index 17de8559b9..41fa172ec6 100644
--- a/backend/tests/unit/core/ipam/test_ipam_reconcile_query.py
+++ b/backend/tests/unit/core/ipam/test_ipam_reconcile_query.py
@@ -6,7 +6,7 @@
from infrahub.core.initialization import create_branch, create_ipam_namespace, get_default_ipnamespace
from infrahub.core.node import Node
from infrahub.core.query.ipam import IPPrefixReconcileQuery
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/migrations/graph/test_003.py b/backend/tests/unit/core/migrations/graph/test_003.py
index d8a0b118d9..ae5358a793 100644
--- a/backend/tests/unit/core/migrations/graph/test_003.py
+++ b/backend/tests/unit/core/migrations/graph/test_003.py
@@ -3,7 +3,7 @@
from infrahub.core.migrations.graph.m003_relationship_parent_optional import Migration003, Migration003Query01
from infrahub.core.node import Node
from infrahub.core.schema import SchemaRoot, internal_schema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.utils import count_relationships
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/migrations/graph/test_012.py b/backend/tests/unit/core/migrations/graph/test_012.py
index 00e162d811..f7d41d91df 100644
--- a/backend/tests/unit/core/migrations/graph/test_012.py
+++ b/backend/tests/unit/core/migrations/graph/test_012.py
@@ -11,7 +11,7 @@
)
from infrahub.core.node import Node
from infrahub.core.schema import AttributeSchema, NodeSchema, RelationshipSchema, SchemaRoot, internal_schema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.utils import count_nodes, count_relationships
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/migrations/graph/test_013.py b/backend/tests/unit/core/migrations/graph/test_013.py
index e515b93a24..31e39c38c7 100644
--- a/backend/tests/unit/core/migrations/graph/test_013.py
+++ b/backend/tests/unit/core/migrations/graph/test_013.py
@@ -12,7 +12,7 @@
)
from infrahub.core.node import Node
from infrahub.core.schema import AttributeSchema, NodeSchema, RelationshipSchema, SchemaRoot, internal_schema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.utils import count_nodes, count_relationships
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/resource_manager/test_ipaddress_pool.py b/backend/tests/unit/core/resource_manager/test_ipaddress_pool.py
index 1e88ae571d..7e369610b2 100644
--- a/backend/tests/unit/core/resource_manager/test_ipaddress_pool.py
+++ b/backend/tests/unit/core/resource_manager/test_ipaddress_pool.py
@@ -5,7 +5,7 @@
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
from infrahub.core.node.resource_manager.ip_address_pool import CoreIPAddressPool
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
from infrahub.exceptions import PoolExhaustedError
diff --git a/backend/tests/unit/core/resource_manager/test_prefix_pool.py b/backend/tests/unit/core/resource_manager/test_prefix_pool.py
index 4695a784e8..134309784f 100644
--- a/backend/tests/unit/core/resource_manager/test_prefix_pool.py
+++ b/backend/tests/unit/core/resource_manager/test_prefix_pool.py
@@ -6,7 +6,7 @@
from infrahub.core.initialization import create_branch
from infrahub.core.node import Node
from infrahub.core.node.resource_manager.ip_prefix_pool import CoreIPPrefixPool
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/schema_manager/test_manager_schema.py b/backend/tests/unit/core/schema_manager/test_manager_schema.py
index 625447051a..23ad98c2f1 100644
--- a/backend/tests/unit/core/schema_manager/test_manager_schema.py
+++ b/backend/tests/unit/core/schema_manager/test_manager_schema.py
@@ -1,9 +1,9 @@
import copy
+import json
import re
import uuid
import pytest
-from deepdiff import DeepDiff
from infrahub_sdk.utils import compare_lists
from infrahub.core import registry
@@ -11,8 +11,6 @@
from infrahub.core.constants import (
AllowOverrideType,
BranchSupportType,
- FilterSchemaKind,
- HashableModelState,
InfrahubKind,
RelationshipDeleteBehavior,
RelationshipKind,
@@ -25,7 +23,8 @@
core_models,
internal_schema,
)
-from infrahub.core.schema_manager import SchemaBranch, SchemaManager
+from infrahub.core.schema.manager import SchemaManager
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
from infrahub.exceptions import SchemaNotFoundError, ValidationError
@@ -1489,513 +1488,23 @@ async def test_schema_branch_validate_count_against_cardinality_invalid(relation
schema_branch.validate_count_against_cardinality()
-async def test_schema_branch_process_filters(
- db: InfrahubDatabase, reset_registry, default_branch: Branch, register_internal_models_schema
-):
- FULL_SCHEMA = {
- "nodes": [
- {
- "name": "Criticality",
- "namespace": "Builtin",
- "default_filter": "name__value",
- "human_friendly_id": ["name__value"],
- "label": "Criticality",
- "attributes": [
- {"name": "name", "kind": "Text", "label": "Name", "unique": True},
- {"name": "level", "kind": "Number", "label": "Level"},
- {"name": "color", "kind": "Text", "label": "Color", "default_value": "#444444"},
- {"name": "description", "kind": "Text", "label": "Description", "optional": True},
- ],
- "relationships": [
- {
- "name": "tags",
- "peer": InfrahubKind.TAG,
- "label": "Tags",
- "optional": True,
- "cardinality": "many",
- },
- {
- "name": "primary_tag",
- "peer": InfrahubKind.TAG,
- "label": "Primary Tag",
- "identifier": "primary_tag__criticality",
- "optional": True,
- "cardinality": "one",
- },
- ],
- },
- {
- "name": "Tag",
- "namespace": "Builtin",
- "label": "Tag",
- "default_filter": "name__value",
- "attributes": [
- {"name": "name", "kind": "Text", "label": "Name", "unique": True},
- {"name": "description", "kind": "Text", "label": "Description", "optional": True},
- ],
- },
- ]
- }
+async def test_schema_branch_from_dict_schema_object():
+ schema = SchemaRoot(**core_models)
schema_branch = SchemaBranch(cache={}, name="test")
- schema_branch.load_schema(schema=SchemaRoot(**FULL_SCHEMA))
- schema_branch.process_filters()
+ schema_branch.load_schema(schema=schema)
- assert len(schema_branch.nodes) == 2
- criticality_dict = schema_branch.get("BuiltinCriticality").model_dump()
- tag_dict = schema_branch.get("BuiltinTag").model_dump()
+ exported = schema_branch.to_dict_schema_object()
- criticality_expected_filters = [
- {
- "id": None,
- "name": "ids",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "hfid",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "name__value",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "name__values",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "name__is_visible",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "name__is_protected",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "name__source__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "name__owner__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "level__value",
- "kind": FilterSchemaKind.NUMBER,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "level__values",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "level__is_visible",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "level__is_protected",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "level__source__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "level__owner__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "color__value",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "color__values",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "color__is_visible",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "color__is_protected",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "color__source__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "color__owner__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "description__value",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "description__values",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "description__is_visible",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "description__is_protected",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "description__source__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "description__owner__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "any__value",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "any__is_visible",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "any__is_protected",
- "kind": FilterSchemaKind.BOOLEAN,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "any__source__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "id": None,
- "name": "any__owner__id",
- "kind": FilterSchemaKind.TEXT,
- "enum": None,
- "object_kind": None,
- "description": None,
- "state": HashableModelState.PRESENT,
- },
- ]
- tag_expected_filters = [
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "ids",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "name__value",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "name__values",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.BOOLEAN,
- "name": "name__is_visible",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.BOOLEAN,
- "name": "name__is_protected",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "name__source__id",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "name__owner__id",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "description__value",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "description__values",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.BOOLEAN,
- "name": "description__is_visible",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.BOOLEAN,
- "name": "description__is_protected",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "description__source__id",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "description__owner__id",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "any__value",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.BOOLEAN,
- "name": "any__is_visible",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.BOOLEAN,
- "name": "any__is_protected",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "any__source__id",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- {
- "description": None,
- "enum": None,
- "id": None,
- "kind": FilterSchemaKind.TEXT,
- "name": "any__owner__id",
- "object_kind": None,
- "state": HashableModelState.PRESENT,
- },
- ]
+ exported_json = json.dumps(exported, default=lambda x: x.dict())
- assert criticality_dict["filters"] == criticality_expected_filters
- assert not DeepDiff(criticality_dict["filters"], criticality_expected_filters, ignore_order=True)
+ exported_dict = json.loads(exported_json)
+ schema_branch_after = SchemaBranch.from_dict_schema_object(data=exported_dict)
- assert tag_dict["filters"] == tag_expected_filters
- assert not DeepDiff(tag_dict["filters"], tag_expected_filters, ignore_order=True)
+ assert (
+ schema_branch_after.get_node(name=InfrahubKind.TAG).get_hash()
+ == schema_branch.get_node(name=InfrahubKind.TAG).get_hash()
+ )
async def test_process_relationships_on_delete_defaults_set(schema_all_in_one):
diff --git a/backend/tests/unit/core/schema_manager/test_parent_component_validation.py b/backend/tests/unit/core/schema_manager/test_parent_component_validation.py
index cfd8831343..641fa5ff10 100644
--- a/backend/tests/unit/core/schema_manager/test_parent_component_validation.py
+++ b/backend/tests/unit/core/schema_manager/test_parent_component_validation.py
@@ -3,7 +3,7 @@
import pytest
from infrahub.core.schema import SchemaRoot
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from .conftest import _get_schema_by_kind
diff --git a/backend/tests/unit/core/schema_manager/test_validate_schema_path.py b/backend/tests/unit/core/schema_manager/test_validate_schema_path.py
index 10c3d35a15..82a01b4f3e 100644
--- a/backend/tests/unit/core/schema_manager/test_validate_schema_path.py
+++ b/backend/tests/unit/core/schema_manager/test_validate_schema_path.py
@@ -7,7 +7,7 @@
from infrahub.core.schema import (
SchemaRoot,
)
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/test_manager_node.py b/backend/tests/unit/core/test_manager_node.py
index f256f8146b..1bf684cbb9 100644
--- a/backend/tests/unit/core/test_manager_node.py
+++ b/backend/tests/unit/core/test_manager_node.py
@@ -8,7 +8,7 @@
from infrahub.core.query.node import NodeToProcess
from infrahub.core.registry import registry
from infrahub.core.schema import NodeSchema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.timestamp import Timestamp
from infrahub.database import InfrahubDatabase
from infrahub.exceptions import NodeNotFoundError
diff --git a/backend/tests/unit/core/test_registry.py b/backend/tests/unit/core/test_registry.py
index f301c2d9ff..a0a99f538a 100644
--- a/backend/tests/unit/core/test_registry.py
+++ b/backend/tests/unit/core/test_registry.py
@@ -1,7 +1,7 @@
from infrahub.core.branch import Branch
from infrahub.core.registry import registry
from infrahub.core.schema import SchemaRoot, internal_schema
-from infrahub.core.schema_manager import SchemaManager
+from infrahub.core.schema.manager import SchemaManager
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/test_relationship.py b/backend/tests/unit/core/test_relationship.py
index f9c3d7d0f7..6b2c90eadd 100644
--- a/backend/tests/unit/core/test_relationship.py
+++ b/backend/tests/unit/core/test_relationship.py
@@ -9,7 +9,7 @@
from infrahub.core.node.resource_manager.ip_prefix_pool import CoreIPPrefixPool
from infrahub.core.query.relationship import RelationshipGetPeerQuery
from infrahub.core.relationship.model import Relationship, RelationshipValidatorList
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.timestamp import Timestamp
from infrahub.database import InfrahubDatabase
diff --git a/backend/tests/unit/core/test_schema_parse_schema_path.py b/backend/tests/unit/core/test_schema_parse_schema_path.py
index 58e3146f45..c0de6cd8aa 100644
--- a/backend/tests/unit/core/test_schema_parse_schema_path.py
+++ b/backend/tests/unit/core/test_schema_parse_schema_path.py
@@ -2,7 +2,7 @@
from infrahub.core import registry
from infrahub.core.schema import AttributePathParsingError, SchemaAttributePath
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
class TestSchemaParseSchemaPath:
diff --git a/backend/tests/unit/git/test_git_rpc.py b/backend/tests/unit/git/test_git_rpc.py
index 3150e444ee..05bcb7bc99 100644
--- a/backend/tests/unit/git/test_git_rpc.py
+++ b/backend/tests/unit/git/test_git_rpc.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Optional
+from typing import TYPE_CHECKING, Any, Optional, Self
from unittest.mock import AsyncMock, patch
from infrahub_sdk import UUIDT, Config, InfrahubClient
@@ -27,7 +27,7 @@
class AsyncContextManagerMock:
- async def __aenter__(self, *args: Any, **kwargs: Any):
+ async def __aenter__(self, *args: Any, **kwargs: Any) -> Self:
return self
async def __aexit__(
@@ -35,10 +35,10 @@ async def __aexit__(
exc_type: Optional[type[BaseException]],
exc_value: Optional[BaseException],
traceback: Optional[TracebackType],
- ):
+ ) -> None:
pass
- def __call__(self, *args: Any, **kwargs: Any):
+ def __call__(self, *args: Any, **kwargs: Any) -> Self:
return self
diff --git a/sync/examples/nautobot-v1_to_infrahub/nautobot/__init__.py b/backend/tests/unit/graphql/auth/query_permission_checker/__init__.py
similarity index 100%
rename from sync/examples/nautobot-v1_to_infrahub/nautobot/__init__.py
rename to backend/tests/unit/graphql/auth/query_permission_checker/__init__.py
diff --git a/backend/tests/unit/graphql/auth/query_permission_checker/test_default_branch_checker.py b/backend/tests/unit/graphql/auth/query_permission_checker/test_default_branch_checker.py
new file mode 100644
index 0000000000..bcfb81fcbd
--- /dev/null
+++ b/backend/tests/unit/graphql/auth/query_permission_checker/test_default_branch_checker.py
@@ -0,0 +1,138 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from unittest.mock import MagicMock
+from uuid import uuid4
+
+import pytest
+
+from infrahub.auth import AccountSession, AuthType
+from infrahub.core.constants import AccountRole, GlobalPermissions, InfrahubKind
+from infrahub.core.node import Node
+from infrahub.core.registry import registry
+from infrahub.exceptions import PermissionDeniedError
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.auth.query_permission_checker.default_branch_checker import DefaultBranchPermissionChecker
+from infrahub.graphql.auth.query_permission_checker.interface import CheckerResolution
+from infrahub.graphql.initialization import GraphqlParams
+from infrahub.permissions.local_backend import LocalPermissionBackend
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.protocols import CoreAccount
+ from infrahub.database import InfrahubDatabase
+ from tests.unit.graphql.conftest import PermissionsHelper
+
+
+class TestDefaultBranchPermission:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+ permissions_helper: PermissionsHelper,
+ ):
+ registry.permission_backends = [LocalPermissionBackend()]
+ permissions_helper._default_branch = default_branch
+
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db, name=GlobalPermissions.EDIT_DEFAULT_BRANCH.value, action=GlobalPermissions.EDIT_DEFAULT_BRANCH.value
+ )
+ await permission.save(db=db)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=[permission])
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ permissions_helper._first = first_account
+ permissions_helper._second = second_account
+
+ @pytest.mark.parametrize(
+ "user",
+ [
+ AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.ADMIN),
+ AccountSession(authenticated=False, account_id="anonymous", auth_type=AuthType.NONE),
+ ],
+ )
+ async def test_supports_default_branch_permission_accounts(
+ self, user: AccountSession, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ):
+ checker = DefaultBranchPermissionChecker()
+ is_supported = await checker.supports(db=db, account_session=user, branch=permissions_helper.default_branch)
+ assert is_supported == user.authenticated
+
+ @pytest.mark.parametrize(
+ "contains_mutation,branch_name",
+ [(True, "main"), (False, "main"), (True, "not_default_branch"), (False, "not_default_branch")],
+ )
+ async def test_account_with_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, contains_mutation: bool, branch_name: str
+ ):
+ checker = DefaultBranchPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.first.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ graphql_query = MagicMock(spec=InfrahubGraphQLQueryAnalyzer)
+ graphql_query.branch = MagicMock()
+ graphql_query.branch.name = branch_name
+ graphql_query.contains_mutation = contains_mutation
+ graphql_query.operation_name = "CreateTags"
+
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+
+ @pytest.mark.parametrize(
+ "contains_mutation,branch_name",
+ [(True, "main"), (False, "main"), (True, "not_default_branch"), (False, "not_default_branch")],
+ )
+ async def test_account_without_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, contains_mutation: bool, branch_name: str
+ ):
+ checker = DefaultBranchPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.second.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ graphql_query = MagicMock(spec=InfrahubGraphQLQueryAnalyzer)
+ graphql_query.branch = MagicMock()
+ graphql_query.branch.name = branch_name
+ graphql_query.contains_mutation = contains_mutation
+ graphql_query.operation_name = "CreateTags"
+
+ if not contains_mutation or branch_name != "main":
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+ else:
+ with pytest.raises(
+ PermissionDeniedError, match=r"You are not allowed to change data in the default branch"
+ ):
+ await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
diff --git a/backend/tests/unit/graphql/auth/query_permission_checker/test_merge_operation_checker.py b/backend/tests/unit/graphql/auth/query_permission_checker/test_merge_operation_checker.py
new file mode 100644
index 0000000000..ed31289eb4
--- /dev/null
+++ b/backend/tests/unit/graphql/auth/query_permission_checker/test_merge_operation_checker.py
@@ -0,0 +1,141 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from unittest.mock import AsyncMock, MagicMock
+from uuid import uuid4
+
+import pytest
+
+from infrahub.auth import AccountSession, AuthType
+from infrahub.core.constants import AccountRole, GlobalPermissions, InfrahubKind
+from infrahub.core.node import Node
+from infrahub.core.registry import registry
+from infrahub.exceptions import PermissionDeniedError
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.auth.query_permission_checker.interface import CheckerResolution
+from infrahub.graphql.auth.query_permission_checker.merge_operation_checker import MergeBranchPermissionChecker
+from infrahub.graphql.initialization import GraphqlParams
+from infrahub.permissions.local_backend import LocalPermissionBackend
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.protocols import CoreAccount
+ from infrahub.database import InfrahubDatabase
+ from tests.unit.graphql.conftest import PermissionsHelper
+
+
+class TestMergeBranchPermission:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ permissions_helper: PermissionsHelper,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+ ):
+ registry.permission_backends = [LocalPermissionBackend()]
+ permissions_helper._default_branch = default_branch
+
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db, name=GlobalPermissions.MERGE_BRANCH.value, action=GlobalPermissions.MERGE_BRANCH.value
+ )
+ await permission.save(db=db)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=[permission])
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ permissions_helper._first = first_account
+ permissions_helper._second = second_account
+
+ @pytest.mark.parametrize(
+ "user",
+ [
+ AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.ADMIN),
+ AccountSession(authenticated=False, account_id="anonymous", auth_type=AuthType.NONE),
+ ],
+ )
+ async def test_supports_merge_branch_permission_accounts(
+ self, user: AccountSession, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ):
+ checker = MergeBranchPermissionChecker()
+ is_supported = await checker.supports(db=db, account_session=user, branch=permissions_helper.default_branch)
+ assert is_supported == user.authenticated
+
+ @pytest.mark.parametrize(
+ "operation_name,checker_resolution",
+ [("BranchMerge", CheckerResolution.TERMINATE), ("BuiltinTagCreate", CheckerResolution.NEXT_CHECKER)],
+ )
+ async def test_account_with_permission(
+ self,
+ operation_name: str,
+ checker_resolution: None | CheckerResolution,
+ db: InfrahubDatabase,
+ permissions_helper: PermissionsHelper,
+ ):
+ checker = MergeBranchPermissionChecker()
+ graphql_query = AsyncMock(spec=InfrahubGraphQLQueryAnalyzer)
+ graphql_query.operation_name = "Foo"
+ graphql_query.operations = [MagicMock()]
+ graphql_query.operations[0].name = operation_name
+
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.first.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == checker_resolution
+
+ @pytest.mark.parametrize(
+ "operation_name,checker_resolution",
+ [("BranchMerge", None), ("BuiltinTagCreate", CheckerResolution.NEXT_CHECKER)],
+ )
+ async def test_account_without_permission(
+ self,
+ operation_name: str,
+ checker_resolution: None | CheckerResolution,
+ db: InfrahubDatabase,
+ permissions_helper: PermissionsHelper,
+ ):
+ checker = MergeBranchPermissionChecker()
+ graphql_query = AsyncMock(spec=InfrahubGraphQLQueryAnalyzer)
+ graphql_query.operation_name = "Foo"
+ graphql_query.operations = [MagicMock()]
+ graphql_query.operations[0].name = operation_name
+
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.second.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ if checker_resolution is None:
+ with pytest.raises(PermissionDeniedError, match=r"You are not allowed to merge a branch"):
+ await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
+ else:
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == checker_resolution
diff --git a/backend/tests/unit/graphql/auth/query_permission_checker/test_object_permission_checker.py b/backend/tests/unit/graphql/auth/query_permission_checker/test_object_permission_checker.py
new file mode 100644
index 0000000000..ab0a12665e
--- /dev/null
+++ b/backend/tests/unit/graphql/auth/query_permission_checker/test_object_permission_checker.py
@@ -0,0 +1,710 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from uuid import uuid4
+
+import pytest
+
+from infrahub.auth import AccountSession, AuthType
+from infrahub.core.account import ObjectPermission
+from infrahub.core.constants import (
+ AccountRole,
+ GlobalPermissions,
+ InfrahubKind,
+ PermissionAction,
+ PermissionDecision,
+)
+from infrahub.core.node import Node
+from infrahub.core.registry import registry
+from infrahub.exceptions import PermissionDeniedError
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.auth.query_permission_checker.interface import CheckerResolution
+from infrahub.graphql.auth.query_permission_checker.object_permission_checker import (
+ AccountManagerPermissionChecker,
+ ObjectPermissionChecker,
+ PermissionManagerPermissionChecker,
+ RepositoryManagerPermissionChecker,
+)
+from infrahub.graphql.initialization import prepare_graphql_params
+from infrahub.permissions.local_backend import LocalPermissionBackend
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.protocols import CoreAccount
+ from infrahub.database import InfrahubDatabase
+ from tests.unit.graphql.conftest import PermissionsHelper
+
+
+QUERY_TAGS = """
+query {
+ BuiltinTag {
+ edges {
+ node {
+ display_label
+ }
+ }
+ }
+}
+"""
+
+QUERY_REPOS = """
+query {
+ CoreRepository {
+ edges {
+ node {
+ display_label
+ }
+ }
+ }
+}
+"""
+
+QUERY_GRAPHQL = """
+query {
+ CoreGraphQLQuery {
+ edges {
+ node {
+ display_label
+ }
+ }
+ }
+}
+"""
+
+QUERY_GRAPHQL_AND_REPO = """
+query {
+ CoreGraphQLQuery {
+ edges {
+ node {
+ display_label
+ repository {
+ node {
+ display_label
+ }
+ }
+ }
+ }
+ }
+}
+"""
+
+MUTATION_ACCOUNT = """
+mutation {
+ CoreAccountCreate(data: {
+ name: {value: "test"}
+ password: {value: "test"}
+ }) {
+ ok
+ }
+}
+"""
+
+MUTATION_ACCOUNT_GROUP = """
+mutation {
+ CoreAccountGroupCreate(data: {
+ name: {value: "test"}
+ }) {
+ ok
+ }
+}
+"""
+
+MUTATION_ACCOUNT_ROLE = """
+mutation {
+ CoreAccountRoleCreate(data: {
+ name: {value: "test"}
+ }) {
+ ok
+ }
+}
+"""
+
+QUERY_ACCOUNT_PROFILE = """
+query {
+ AccountProfile {
+ name {
+ value
+ }
+ }
+}
+"""
+
+MUTATION_GLOBAL_PERMISSION = """
+mutation {
+ CoreGlobalPermissionCreate(data: {
+ name: {value: "Merge branch"}
+ action: {value: "merge_branch"}
+ }) {
+ ok
+ object {
+ identifier {
+ value
+ }
+ }
+ }
+}
+"""
+
+MUTATION_OBJECT_PERMISSION = """
+mutation {
+ CoreObjectPermissionCreate(data: {
+ branch: {value: "*"}
+ namespace: {value: "*"}
+ name: {value: "*"}
+ }) {
+ ok
+ object {
+ identifier {
+ value
+ }
+ }
+ }
+}
+"""
+
+QUERY_ACCOUNT_PERMISSIONS = """
+query {
+ InfrahubPermissions {
+ global_permissions {
+ edges {
+ node {
+ identifier
+ }
+ }
+ }
+ object_permissions {
+ edges {
+ node {
+ identifier
+ }
+ }
+ }
+ }
+}
+"""
+
+MUTATION_REPOSITORY = """
+mutation {
+ CoreRepositoryCreate(data: {
+ name: {value: "Test"}
+ location: {value: "/var/random"}
+ }) {
+ ok
+ }
+}
+"""
+
+MUTATION_READONLY_REPOSITORY = """
+mutation {
+ CoreReadOnlyRepositoryCreate(data: {
+ name: {value: "Test"}
+ location: {value: "/var/random"}
+ }) {
+ ok
+ }
+}
+"""
+
+MUTATION_GENERIC_REPOSITORY = """
+mutation {
+ CoreGenericRepositoryUpdate(data: {
+ name: {value: "Test"}
+ location: {value: "/var/random"}
+ }) {
+ ok
+ }
+}
+"""
+
+
+class TestObjectPermissions:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ permissions_helper: PermissionsHelper,
+ first_account: CoreAccount,
+ ):
+ registry.permission_backends = [LocalPermissionBackend()]
+ permissions_helper._default_branch = default_branch
+
+ permissions = []
+ for object_permission in [
+ ObjectPermission(
+ id="",
+ branch="main",
+ namespace="Builtin",
+ name="*",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ObjectPermission(
+ id="",
+ branch="main",
+ namespace="Core",
+ name="GraphQLQuery",
+ action=PermissionAction.VIEW.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ]:
+ obj = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
+ await obj.new(
+ db=db,
+ branch=object_permission.branch,
+ namespace=object_permission.namespace,
+ name=object_permission.name,
+ action=object_permission.action,
+ decision=object_permission.decision,
+ )
+ await obj.save(db=db)
+ permissions.append(obj)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=permissions)
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ permissions_helper._first = first_account
+
+ async def test_first_account_tags(self, db: InfrahubDatabase, permissions_helper: PermissionsHelper) -> None:
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=QUERY_TAGS, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+ perms = ObjectPermissionChecker()
+ session = AccountSession(
+ authenticated=True,
+ account_id=permissions_helper.first.id,
+ session_id=str(uuid4()),
+ auth_type=AuthType.JWT,
+ )
+
+ await perms.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ branch=permissions_helper.default_branch,
+ query_parameters=gql_params,
+ )
+
+ async def test_first_account_repos(self, db: InfrahubDatabase, permissions_helper: PermissionsHelper) -> None:
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=QUERY_REPOS, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+ perms = ObjectPermissionChecker()
+ session = AccountSession(
+ authenticated=True,
+ account_id=permissions_helper.first.id,
+ session_id=str(uuid4()),
+ auth_type=AuthType.JWT,
+ )
+
+ with pytest.raises(
+ PermissionDeniedError,
+ match="You do not have the following permission: object:main:Core:Repository:view:allow",
+ ):
+ await perms.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ branch=permissions_helper.default_branch,
+ query_parameters=gql_params,
+ )
+
+ async def test_first_account_graphql(self, db: InfrahubDatabase, permissions_helper: PermissionsHelper) -> None:
+ """The user should have permissions to list GraphQLQueries."""
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=QUERY_GRAPHQL, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+ perms = ObjectPermissionChecker()
+ session = AccountSession(
+ authenticated=True,
+ account_id=permissions_helper.first.id,
+ session_id=str(uuid4()),
+ auth_type=AuthType.JWT,
+ )
+
+ await perms.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ branch=permissions_helper.default_branch,
+ query_parameters=gql_params,
+ )
+
+ async def test_first_account_graphql_and_repos(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ) -> None:
+ """The user should have permissions to list GraphQLQueries but not repositories linked to them"""
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=QUERY_GRAPHQL_AND_REPO, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+ perms = ObjectPermissionChecker()
+ session = AccountSession(
+ authenticated=True,
+ account_id=permissions_helper.first.id,
+ session_id=str(uuid4()),
+ auth_type=AuthType.JWT,
+ )
+
+ with pytest.raises(PermissionDeniedError, match="Repository:view:allow"):
+ await perms.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ branch=permissions_helper.default_branch,
+ query_parameters=gql_params,
+ )
+
+
+class TestAccountManagerPermissions:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ permissions_helper: PermissionsHelper,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+ ):
+ registry.permission_backends = [LocalPermissionBackend()]
+ permissions_helper._default_branch = default_branch
+
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db, name=GlobalPermissions.MANAGE_ACCOUNTS.value, action=GlobalPermissions.MANAGE_ACCOUNTS.value
+ )
+ await permission.save(db=db)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=[permission])
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ permissions_helper._first = first_account
+ permissions_helper._second = second_account
+
+ @pytest.mark.parametrize(
+ "user",
+ [
+ AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.ADMIN),
+ AccountSession(authenticated=False, account_id="anonymous", auth_type=AuthType.NONE),
+ ],
+ )
+ async def test_supports_manage_accounts_permission_accounts(
+ self, user: AccountSession, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ):
+ checker = AccountManagerPermissionChecker()
+ is_supported = await checker.supports(db=db, account_session=user, branch=permissions_helper.default_branch)
+ assert is_supported == user.authenticated
+
+ @pytest.mark.parametrize("operation", [MUTATION_ACCOUNT, MUTATION_ACCOUNT_GROUP, MUTATION_ACCOUNT_ROLE])
+ async def test_account_with_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, operation: str
+ ):
+ checker = AccountManagerPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.first.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=operation, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+
+ @pytest.mark.parametrize(
+ "operation,must_raise",
+ [
+ (MUTATION_ACCOUNT, True),
+ (MUTATION_ACCOUNT_GROUP, True),
+ (MUTATION_ACCOUNT_ROLE, True),
+ (QUERY_TAGS, False),
+ (QUERY_ACCOUNT_PROFILE, False),
+ ],
+ )
+ async def test_account_without_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, operation: str, must_raise: bool
+ ):
+ checker = AccountManagerPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.second.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=operation, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+
+ if not must_raise:
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+ else:
+ with pytest.raises(
+ PermissionDeniedError, match=r"You do not have the permission to manage user accounts, groups or roles"
+ ):
+ await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+
+
+class TestPermissionManagerPermissions:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ permissions_helper: PermissionsHelper,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+ ):
+ registry.permission_backends = [LocalPermissionBackend()]
+ permissions_helper._default_branch = default_branch
+
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db, name=GlobalPermissions.MANAGE_PERMISSIONS.value, action=GlobalPermissions.MANAGE_PERMISSIONS.value
+ )
+ await permission.save(db=db)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=[permission])
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ permissions_helper._first = first_account
+ permissions_helper._second = second_account
+
+ @pytest.mark.parametrize(
+ "user",
+ [
+ AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.ADMIN),
+ AccountSession(authenticated=False, account_id="anonymous", auth_type=AuthType.NONE),
+ ],
+ )
+ async def test_supports_manage_accounts_permission_accounts(
+ self, user: AccountSession, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ):
+ checker = PermissionManagerPermissionChecker()
+ is_supported = await checker.supports(db=db, account_session=user, branch=permissions_helper.default_branch)
+ assert is_supported == user.authenticated
+
+ @pytest.mark.parametrize(
+ "operation", [MUTATION_GLOBAL_PERMISSION, MUTATION_OBJECT_PERMISSION, QUERY_ACCOUNT_PERMISSIONS]
+ )
+ async def test_account_with_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, operation: str
+ ):
+ checker = PermissionManagerPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.first.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=operation, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+
+ @pytest.mark.parametrize(
+ "operation,must_raise",
+ [
+ (MUTATION_GLOBAL_PERMISSION, True),
+ (MUTATION_OBJECT_PERMISSION, True),
+ (QUERY_TAGS, False),
+ (QUERY_ACCOUNT_PERMISSIONS, False),
+ ],
+ )
+ async def test_account_without_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, operation: str, must_raise: bool
+ ):
+ checker = PermissionManagerPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.second.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=operation, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+
+ if not must_raise:
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+ else:
+ with pytest.raises(PermissionDeniedError, match=r"You do not have the permission to manage permissions"):
+ await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+
+
+class TestRepositoryManagerPermissions:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ permissions_helper: PermissionsHelper,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+ ):
+ registry.permission_backends = [LocalPermissionBackend()]
+ permissions_helper._default_branch = default_branch
+
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db, name=GlobalPermissions.MANAGE_REPOSITORIES.value, action=GlobalPermissions.MANAGE_REPOSITORIES.value
+ )
+ await permission.save(db=db)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=[permission])
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ permissions_helper._first = first_account
+ permissions_helper._second = second_account
+
+ @pytest.mark.parametrize(
+ "user",
+ [
+ AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.ADMIN),
+ AccountSession(authenticated=False, account_id="anonymous", auth_type=AuthType.NONE),
+ ],
+ )
+ async def test_supports_manage_repositories_permission_accounts(
+ self, user: AccountSession, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ):
+ checker = AccountManagerPermissionChecker()
+ is_supported = await checker.supports(db=db, account_session=user, branch=permissions_helper.default_branch)
+ assert is_supported == user.authenticated
+
+ @pytest.mark.parametrize(
+ "operation", [MUTATION_REPOSITORY, MUTATION_READONLY_REPOSITORY, MUTATION_GENERIC_REPOSITORY]
+ )
+ async def test_account_with_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, operation: str
+ ):
+ checker = RepositoryManagerPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.first.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=operation, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+
+ @pytest.mark.parametrize(
+ "operation,must_raise",
+ [
+ (MUTATION_REPOSITORY, True),
+ (MUTATION_READONLY_REPOSITORY, True),
+ (MUTATION_GENERIC_REPOSITORY, True),
+ (QUERY_TAGS, False),
+ ],
+ )
+ async def test_account_without_permission(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper, operation: str, must_raise: bool
+ ):
+ checker = RepositoryManagerPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.second.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=permissions_helper.default_branch)
+ analyzed_query = InfrahubGraphQLQueryAnalyzer(
+ query=operation, schema=gql_params.schema, branch=permissions_helper.default_branch
+ )
+
+ if not must_raise:
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
+ else:
+ with pytest.raises(PermissionDeniedError, match=r"You do not have the permission to manage repositories"):
+ await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=analyzed_query,
+ query_parameters=gql_params,
+ branch=permissions_helper.default_branch,
+ )
diff --git a/backend/tests/unit/graphql/auth/query_permission_checker/test_super_admin_checker.py b/backend/tests/unit/graphql/auth/query_permission_checker/test_super_admin_checker.py
new file mode 100644
index 0000000000..e4f715f4a8
--- /dev/null
+++ b/backend/tests/unit/graphql/auth/query_permission_checker/test_super_admin_checker.py
@@ -0,0 +1,99 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from unittest.mock import MagicMock
+from uuid import uuid4
+
+import pytest
+
+from infrahub.auth import AccountSession, AuthType
+from infrahub.core.constants import AccountRole, GlobalPermissions, InfrahubKind
+from infrahub.core.node import Node
+from infrahub.core.registry import registry
+from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.auth.query_permission_checker.interface import CheckerResolution
+from infrahub.graphql.auth.query_permission_checker.super_admin_checker import SuperAdminPermissionChecker
+from infrahub.graphql.initialization import GraphqlParams
+from infrahub.permissions.local_backend import LocalPermissionBackend
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.protocols import CoreAccount
+ from infrahub.database import InfrahubDatabase
+ from tests.unit.graphql.conftest import PermissionsHelper
+
+
+class TestSuperAdminPermission:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+ permissions_helper: PermissionsHelper,
+ ):
+ registry.permission_backends = [LocalPermissionBackend()]
+ permissions_helper._default_branch = default_branch
+
+ permission = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await permission.new(
+ db=db, name=GlobalPermissions.SUPER_ADMIN.value, action=GlobalPermissions.SUPER_ADMIN.value
+ )
+ await permission.save(db=db)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=[permission])
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ permissions_helper._first = first_account
+ permissions_helper._second = second_account
+
+ @pytest.mark.parametrize(
+ "user",
+ [
+ AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.ADMIN),
+ AccountSession(authenticated=False, account_id="anonymous", auth_type=AuthType.NONE),
+ ],
+ )
+ async def test_supports_super_admin_permission_accounts(
+ self, user: AccountSession, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ):
+ checker = SuperAdminPermissionChecker()
+ is_supported = await checker.supports(db=db, account_session=user, branch=permissions_helper.default_branch)
+ assert is_supported == user.authenticated
+
+ async def test_account_with_permission(self, db: InfrahubDatabase, permissions_helper: PermissionsHelper):
+ checker = SuperAdminPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.first.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=MagicMock(spec=InfrahubGraphQLQueryAnalyzer),
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.TERMINATE
+
+ async def test_account_without_permission(self, db: InfrahubDatabase, permissions_helper: PermissionsHelper):
+ checker = SuperAdminPermissionChecker()
+ session = AccountSession(
+ authenticated=True, account_id=permissions_helper.second.id, session_id=str(uuid4()), auth_type=AuthType.JWT
+ )
+ resolution = await checker.check(
+ db=db,
+ account_session=session,
+ analyzed_query=MagicMock(spec=InfrahubGraphQLQueryAnalyzer),
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=permissions_helper.default_branch,
+ )
+ assert resolution == CheckerResolution.NEXT_CHECKER
diff --git a/backend/tests/unit/graphql/auth/test_anonymous_checker.py b/backend/tests/unit/graphql/auth/test_anonymous_checker.py
index 89b1555314..e06900cb64 100644
--- a/backend/tests/unit/graphql/auth/test_anonymous_checker.py
+++ b/backend/tests/unit/graphql/auth/test_anonymous_checker.py
@@ -3,36 +3,56 @@
import pytest
from infrahub.auth import AccountSession, AuthType
+from infrahub.core.branch import Branch
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import AuthorizationError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
from infrahub.graphql.auth.query_permission_checker.anonymous_checker import AnonymousGraphQLPermissionChecker
+from infrahub.graphql.initialization import GraphqlParams
class TestAnonymousAuthChecker:
def setup_method(self):
self.account_session = AccountSession(account_id="abc", auth_type=AuthType.JWT)
self.graphql_query = AsyncMock(spec=InfrahubGraphQLQueryAnalyzer)
+ self.query_parameters = MagicMock(spec=GraphqlParams)
self.mock_anonymous_setting_get = MagicMock(return_value=True)
self.checker = AnonymousGraphQLPermissionChecker(self.mock_anonymous_setting_get)
@pytest.mark.parametrize("is_authenticated,is_supported", [(True, False), (False, True)])
- async def test_supports_unauthenticated_accounts(self, is_authenticated, is_supported):
+ async def test_supports_unauthenticated_accounts(
+ self, db: InfrahubDatabase, branch: Branch, is_authenticated, is_supported
+ ):
self.account_session.authenticated = is_authenticated
- has_support = await self.checker.supports(self.account_session)
+ has_support = await self.checker.supports(db=db, account_session=self.account_session, branch=branch)
assert is_supported is has_support
@pytest.mark.parametrize("anonymous_setting,query_has_mutations", [(False, False), (False, True), (True, True)])
- async def test_failures_raise_error(self, anonymous_setting, query_has_mutations):
+ async def test_failures_raise_error(
+ self, db: InfrahubDatabase, branch: Branch, anonymous_setting, query_has_mutations
+ ):
self.mock_anonymous_setting_get.return_value = anonymous_setting
self.graphql_query.contains_mutation = query_has_mutations
with pytest.raises(AuthorizationError):
- await self.checker.check(self.graphql_query)
-
- async def test_check_passes(self):
+ await self.checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=self.query_parameters,
+ branch=branch,
+ )
+
+ async def test_check_passes(self, db: InfrahubDatabase, branch: Branch):
self.mock_anonymous_setting_get.return_value = True
self.graphql_query.contains_mutation = False
- await self.checker.check(self.graphql_query)
+ await self.checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=self.query_parameters,
+ branch=branch,
+ )
diff --git a/backend/tests/unit/graphql/auth/test_default_checker.py b/backend/tests/unit/graphql/auth/test_default_checker.py
index 53fd65efbb..d90d1e3f62 100644
--- a/backend/tests/unit/graphql/auth/test_default_checker.py
+++ b/backend/tests/unit/graphql/auth/test_default_checker.py
@@ -1,12 +1,15 @@
-from unittest.mock import AsyncMock
+from unittest.mock import AsyncMock, MagicMock
import pytest
from infrahub.auth import AccountSession, AuthType
+from infrahub.core.branch import Branch
from infrahub.core.constants import AccountRole
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import AuthorizationError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
from infrahub.graphql.auth.query_permission_checker.default_checker import DefaultGraphQLPermissionChecker
+from infrahub.graphql.initialization import GraphqlParams
class TestDefaultAuthChecker:
@@ -16,13 +19,19 @@ def setup_method(self):
self.checker = DefaultGraphQLPermissionChecker()
@pytest.mark.parametrize("role", [x.value for x in AccountRole])
- async def test_supports_all_accounts(self, role):
+ async def test_supports_all_accounts(self, db: InfrahubDatabase, branch: Branch, role):
self.account_session.role = role
- is_supported = await self.checker.supports(self.account_session)
+ is_supported = await self.checker.supports(db=db, account_session=self.account_session, branch=branch)
assert is_supported is True
- async def test_always_raises_error(self):
+ async def test_always_raises_error(self, db: InfrahubDatabase, branch: Branch):
with pytest.raises(AuthorizationError):
- await self.checker.check(self.graphql_query)
+ await self.checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=branch,
+ )
diff --git a/backend/tests/unit/graphql/auth/test_parent_checker.py b/backend/tests/unit/graphql/auth/test_parent_checker.py
index 89e537b735..84f2c1d0ff 100644
--- a/backend/tests/unit/graphql/auth/test_parent_checker.py
+++ b/backend/tests/unit/graphql/auth/test_parent_checker.py
@@ -1,41 +1,68 @@
-from unittest.mock import AsyncMock
+from unittest.mock import AsyncMock, MagicMock
import pytest
from infrahub.auth import AccountSession, AuthType
+from infrahub.core.branch import Branch
from infrahub.core.constants import AccountRole
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import PermissionDeniedError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
from infrahub.graphql.auth.query_permission_checker.checker import GraphQLQueryPermissionChecker
-from infrahub.graphql.auth.query_permission_checker.interface import GraphQLQueryPermissionCheckerInterface
+from infrahub.graphql.auth.query_permission_checker.interface import (
+ CheckerResolution,
+ GraphQLQueryPermissionCheckerInterface,
+)
+from infrahub.graphql.initialization import GraphqlParams
class TestParentAuthChecker:
def setup_method(self):
self.account_session = AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.ADMIN)
self.graphql_query = AsyncMock(spec=InfrahubGraphQLQueryAnalyzer)
+ self.query_parameters = MagicMock(spec=GraphqlParams)
self.sub_auth_checker_one = AsyncMock(spec=GraphQLQueryPermissionCheckerInterface)
self.sub_auth_checker_two = AsyncMock(spec=GraphQLQueryPermissionCheckerInterface)
self.sub_auth_checker_one.supports.return_value = False
self.sub_auth_checker_two.supports.return_value = True
+ self.sub_auth_checker_one.check = AsyncMock()
+ self.sub_auth_checker_one.check.return_value = CheckerResolution.TERMINATE
+ self.sub_auth_checker_two.check = AsyncMock()
+ self.sub_auth_checker_two.check.return_value = CheckerResolution.TERMINATE
self.parent_checker = GraphQLQueryPermissionChecker([self.sub_auth_checker_one, self.sub_auth_checker_two])
- async def __call_system_under_test(self):
- await self.parent_checker.check(self.account_session, self.graphql_query)
+ async def __call_system_under_test(self, db: InfrahubDatabase, branch: Branch):
+ await self.parent_checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=self.query_parameters,
+ branch=branch,
+ )
- async def test_only_checks_one(self):
- await self.__call_system_under_test()
+ async def test_only_checks_one(self, db: InfrahubDatabase, branch: Branch):
+ await self.__call_system_under_test(db=db, branch=branch)
- self.sub_auth_checker_one.supports.assert_awaited_once_with(self.account_session)
- self.sub_auth_checker_two.supports.assert_awaited_once_with(self.account_session)
+ self.sub_auth_checker_one.supports.assert_awaited_once_with(
+ db=db, account_session=self.account_session, branch=branch
+ )
+ self.sub_auth_checker_two.supports.assert_awaited_once_with(
+ db=db, account_session=self.account_session, branch=branch
+ )
self.sub_auth_checker_one.check.assert_not_awaited()
- self.sub_auth_checker_two.check.assert_awaited_once_with(self.graphql_query)
+ self.sub_auth_checker_two.check.assert_awaited_once_with(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=self.query_parameters,
+ branch=branch,
+ )
- async def test_error_if_no_support(self):
+ async def test_error_if_no_support(self, db: InfrahubDatabase, branch: Branch):
self.sub_auth_checker_two.supports.return_value = False
with pytest.raises(PermissionDeniedError):
- await self.__call_system_under_test()
+ await self.__call_system_under_test(db=db, branch=branch)
self.sub_auth_checker_one.check.assert_not_awaited()
self.sub_auth_checker_two.check.assert_not_awaited()
diff --git a/backend/tests/unit/graphql/auth/test_read_only_checker.py b/backend/tests/unit/graphql/auth/test_read_only_checker.py
index 92f848f08d..e1a13b921c 100644
--- a/backend/tests/unit/graphql/auth/test_read_only_checker.py
+++ b/backend/tests/unit/graphql/auth/test_read_only_checker.py
@@ -1,55 +1,77 @@
-from unittest.mock import AsyncMock
+from unittest.mock import AsyncMock, MagicMock
import pytest
from graphql import OperationType
from infrahub_sdk.analyzer import GraphQLOperation
from infrahub.auth import AccountSession, AuthType
+from infrahub.core.branch import Branch
from infrahub.core.constants import AccountRole
+from infrahub.database import InfrahubDatabase
from infrahub.exceptions import PermissionDeniedError
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
from infrahub.graphql.auth.query_permission_checker.read_only_checker import ReadOnlyGraphQLPermissionChecker
+from infrahub.graphql.initialization import GraphqlParams
class TestReadOnlyAuthChecker:
def setup_method(self):
self.account_session = AccountSession(account_id="abc", auth_type=AuthType.JWT, role=AccountRole.READ_ONLY)
self.graphql_query = AsyncMock(spec=InfrahubGraphQLQueryAnalyzer)
+ self.query_parameters = MagicMock(spec=GraphqlParams)
self.checker = ReadOnlyGraphQLPermissionChecker()
@pytest.mark.parametrize("role", [AccountRole.ADMIN, AccountRole.READ_WRITE])
- async def test_doesnt_supports_other_accounts(self, role):
+ async def test_doesnt_supports_other_accounts(self, db: InfrahubDatabase, branch: Branch, role):
self.account_session.role = role
- is_supported = await self.checker.supports(self.account_session)
+ is_supported = await self.checker.supports(db=db, account_session=self.account_session, branch=branch)
assert is_supported is False
- async def test_supports_read_only_accounts(self):
+ async def test_supports_read_only_accounts(self, db: InfrahubDatabase, branch: Branch):
self.account_session.role = AccountRole.READ_ONLY
- is_supported = await self.checker.supports(self.account_session)
+ is_supported = await self.checker.supports(db=db, account_session=self.account_session, branch=branch)
assert is_supported is True
- async def test_illegal_mutation_raises_error(self):
+ async def test_illegal_mutation_raises_error(self, db: InfrahubDatabase, branch: Branch):
self.graphql_query.contains_mutation = True
self.graphql_query.operations = [
GraphQLOperation(name="ThisIsNotAllowed", operation_type=OperationType.MUTATION)
]
with pytest.raises(PermissionDeniedError):
- await self.checker.check(self.graphql_query)
-
- async def test_legal_mutation_is_okay(self):
+ await self.checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=self.query_parameters,
+ branch=branch,
+ )
+
+ async def test_legal_mutation_is_okay(self, db: InfrahubDatabase, branch: Branch):
self.checker.allowed_readonly_mutations = ["ThisIsAllowed"]
self.graphql_query.contains_mutation = True
self.graphql_query.operations = [GraphQLOperation(name="ThisIsAllowed", operation_type=OperationType.MUTATION)]
- await self.checker.check(self.graphql_query)
+ await self.checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=self.query_parameters,
+ branch=branch,
+ )
- async def test_query_is_okay(self):
+ async def test_query_is_okay(self, db: InfrahubDatabase, branch: Branch):
self.graphql_query.contains_mutation = False
self.graphql_query.operations = [GraphQLOperation(name="ThisIsAQuery", operation_type=OperationType.QUERY)]
- await self.checker.check(self.graphql_query)
+ await self.checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=self.query_parameters,
+ branch=branch,
+ )
diff --git a/backend/tests/unit/graphql/auth/test_read_write_checker.py b/backend/tests/unit/graphql/auth/test_read_write_checker.py
index 3dbbf38f8c..1f9f59bceb 100644
--- a/backend/tests/unit/graphql/auth/test_read_write_checker.py
+++ b/backend/tests/unit/graphql/auth/test_read_write_checker.py
@@ -1,11 +1,14 @@
-from unittest.mock import AsyncMock
+from unittest.mock import AsyncMock, MagicMock
import pytest
from infrahub.auth import AccountSession, AuthType
+from infrahub.core.branch import Branch
from infrahub.core.constants import AccountRole
+from infrahub.database import InfrahubDatabase
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
from infrahub.graphql.auth.query_permission_checker.read_write_checker import ReadWriteGraphQLPermissionChecker
+from infrahub.graphql.initialization import GraphqlParams
class TestReadWriteAuthChecker:
@@ -15,22 +18,28 @@ def setup_method(self):
self.checker = ReadWriteGraphQLPermissionChecker()
@pytest.mark.parametrize("role", [AccountRole.ADMIN, AccountRole.READ_WRITE])
- async def test_supports_readwrite_accounts(self, role):
+ async def test_supports_readwrite_accounts(self, db: InfrahubDatabase, branch: Branch, role):
self.account_session.role = role
- is_supported = await self.checker.supports(self.account_session)
+ is_supported = await self.checker.supports(db=db, account_session=self.account_session, branch=branch)
assert is_supported is True
- async def test_doesnt_support_readonly_accounts(self):
+ async def test_doesnt_support_readonly_accounts(self, db: InfrahubDatabase, branch: Branch):
self.account_session.role = AccountRole.READ_ONLY
- is_supported = await self.checker.supports(self.account_session)
+ is_supported = await self.checker.supports(db=db, account_session=self.account_session, branch=branch)
assert is_supported is False
@pytest.mark.parametrize("contains_mutations", [True, False])
- async def test_never_raises_error(self, contains_mutations):
+ async def test_never_raises_error(self, db: InfrahubDatabase, branch: Branch, contains_mutations):
self.graphql_query.contains_mutations = contains_mutations
- await self.checker.check(self.graphql_query)
+ await self.checker.check(
+ db=db,
+ account_session=self.account_session,
+ analyzed_query=self.graphql_query,
+ query_parameters=MagicMock(spec=GraphqlParams),
+ branch=branch,
+ )
diff --git a/backend/tests/unit/graphql/conftest.py b/backend/tests/unit/graphql/conftest.py
index 5f4f7ac9d4..dd22ff44d6 100644
--- a/backend/tests/unit/graphql/conftest.py
+++ b/backend/tests/unit/graphql/conftest.py
@@ -1,13 +1,52 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
import pytest
from infrahub.dependencies.registry import build_component_registry
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.protocols import CoreAccount
+
@pytest.fixture(scope="module", autouse=True)
def load_component_dependency_registry():
build_component_registry()
+class PermissionsHelper:
+ def __init__(self) -> None:
+ self._first: None | CoreAccount = None
+ self._second: None | CoreAccount = None
+ self._default_branch: None | Branch = None
+
+ @property
+ def first(self) -> CoreAccount:
+ if self._first:
+ return self._first
+
+ raise NotImplementedError()
+
+ @property
+ def second(self) -> CoreAccount:
+ if self._second:
+ return self._second
+
+ raise NotImplementedError()
+
+ @property
+ def default_branch(self) -> Branch:
+ if self._default_branch:
+ return self._default_branch
+
+
+@pytest.fixture(scope="module")
+def permissions_helper() -> PermissionsHelper:
+ return PermissionsHelper()
+
+
@pytest.fixture
def query_01() -> str:
"""Simple query with one document"""
diff --git a/backend/tests/unit/graphql/mutations/test_branch.py b/backend/tests/unit/graphql/mutations/test_branch.py
index 32650624f3..11cd8a8f39 100644
--- a/backend/tests/unit/graphql/mutations/test_branch.py
+++ b/backend/tests/unit/graphql/mutations/test_branch.py
@@ -7,7 +7,7 @@
from infrahub.core.initialization import create_branch
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.message_bus import messages
from infrahub.services import InfrahubServices
from tests.adapters.message_bus import BusRecorder
diff --git a/backend/tests/unit/graphql/mutations/test_ipam.py b/backend/tests/unit/graphql/mutations/test_ipam.py
index bf9401d8c8..98b8942ff2 100644
--- a/backend/tests/unit/graphql/mutations/test_ipam.py
+++ b/backend/tests/unit/graphql/mutations/test_ipam.py
@@ -6,9 +6,9 @@
from infrahub.core.branch import Branch
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
CREATE_IPPREFIX = """
mutation CreatePrefix($prefix: String!) {
diff --git a/backend/tests/unit/graphql/mutations/test_menu.py b/backend/tests/unit/graphql/mutations/test_menu.py
new file mode 100644
index 0000000000..857d8f6072
--- /dev/null
+++ b/backend/tests/unit/graphql/mutations/test_menu.py
@@ -0,0 +1,115 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from infrahub.menu.constants import MenuSection
+from infrahub.menu.models import MenuItemDefinition
+from infrahub.services import InfrahubServices
+from tests.helpers.graphql import graphql_mutation
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.database import InfrahubDatabase
+
+
+async def test_menu_create(db: InfrahubDatabase, register_core_models_schema: None, default_branch: Branch):
+ service = InfrahubServices(database=db)
+
+ CREATE_MENU = """
+ mutation CoreMenuItemCreate {
+ CoreMenuItemCreate(
+ data: {
+ namespace: { value: "Builtin" }
+ name: { value: "TestCar" }
+ }
+ ) {
+ ok
+ }
+ }
+ """
+
+ result = await graphql_mutation(
+ query=CREATE_MENU,
+ db=db,
+ service=service,
+ )
+ assert "Builtin is not valid" in result.errors[0].args[0]
+
+
+async def test_menu_update_protected(db: InfrahubDatabase, register_core_models_schema: None, default_branch: Branch):
+ service = InfrahubServices(database=db)
+
+ menu_item = MenuItemDefinition(
+ namespace="Builtin",
+ name="Branches",
+ label="Branches",
+ path="/branche",
+ icon="mdi:layers-triple",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ )
+ obj = await menu_item.to_node(db=db)
+ await obj.save(db=db)
+
+ UPDATE_MENU = """
+ mutation CoreMenuItemUpdate($id: String!) {
+ CoreMenuItemUpdate(
+ data: {
+ id: $id
+ name: { value: "TestCar" }
+ }
+ ) {
+ ok
+ }
+ }
+ """
+
+ result = await graphql_mutation(
+ query=UPDATE_MENU,
+ db=db,
+ variables={"id": obj.id},
+ service=service,
+ )
+
+ assert result.errors
+ assert "This object is protected" in result.errors[0].args[0]
+
+
+async def test_menu_delete_protected(db: InfrahubDatabase, register_core_models_schema: None, default_branch: Branch):
+ service = InfrahubServices(database=db)
+
+ menu_item = MenuItemDefinition(
+ namespace="Builtin",
+ name="Branches",
+ label="Branches",
+ path="/branche",
+ icon="mdi:layers-triple",
+ protected=True,
+ section=MenuSection.INTERNAL,
+ order_weight=1000,
+ )
+ obj = await menu_item.to_node(db=db)
+ await obj.save(db=db)
+
+ DELETE_MENU = """
+ mutation CoreMenuItemDelete($id: String!) {
+ CoreMenuItemDelete(
+ data: {
+ id: $id
+ }
+ ) {
+ ok
+ }
+ }
+ """
+
+ result = await graphql_mutation(
+ query=DELETE_MENU,
+ db=db,
+ variables={"id": obj.id},
+ service=service,
+ )
+
+ assert result.errors
+ assert "This object is protected" in result.errors[0].args[0]
diff --git a/backend/tests/unit/graphql/mutations/test_proposed_change.py b/backend/tests/unit/graphql/mutations/test_proposed_change.py
index 136fd5c983..c43ae7303c 100644
--- a/backend/tests/unit/graphql/mutations/test_proposed_change.py
+++ b/backend/tests/unit/graphql/mutations/test_proposed_change.py
@@ -2,12 +2,16 @@
from graphql import graphql
+from infrahub.auth import AccountSession
from infrahub.core.branch import Branch
from infrahub.core.constants import CheckType, InfrahubKind
+from infrahub.core.initialization import create_branch
from infrahub.core.node import Node
+from infrahub.core.registry import registry
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.message_bus import messages
+from infrahub.permissions.local_backend import LocalPermissionBackend
from infrahub.services import InfrahubServices
from tests.adapters.message_bus import BusRecorder
from tests.helpers.graphql import graphql_mutation
@@ -190,3 +194,40 @@ async def test_update_merged_proposed_change(db: InfrahubDatabase, register_core
assert update_status.errors
assert "A proposed change in the merged state is not allowed to be updated" in str(update_status.errors[0])
+
+
+async def test_merge_proposed_change_permission_failure(
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ session_first_account: AccountSession,
+ session_admin: AccountSession,
+):
+ registry.permission_backends = [LocalPermissionBackend()]
+
+ branch_name = "merge-proposed-change-perm"
+ await create_branch(branch_name=branch_name, db=db)
+
+ proposed_change = await Node.init(db=db, schema=InfrahubKind.PROPOSEDCHANGE)
+ await proposed_change.new(
+ db=db, name="pc-merge-perm-1234", destination_branch="main", source_branch=branch_name, state="open"
+ )
+ await proposed_change.save(db=db)
+
+ update_status = await graphql_mutation(
+ query=UPDATE_PROPOSED_CHANGE,
+ db=db,
+ variables={"proposed_change": proposed_change.id, "state": "merged"},
+ account_session=session_first_account,
+ )
+
+ assert update_status.errors
+ assert "You do not have the permission to merge proposed changes" == update_status.errors[0].message
+
+ update_status = await graphql_mutation(
+ query=UPDATE_PROPOSED_CHANGE,
+ db=db,
+ variables={"proposed_change": proposed_change.id, "state": "merged"},
+ account_session=session_admin,
+ )
+
+ assert not update_status.errors
diff --git a/backend/tests/unit/graphql/mutations/test_resource_manager.py b/backend/tests/unit/graphql/mutations/test_resource_manager.py
index 99b0dee5fc..89bebf72a0 100644
--- a/backend/tests/unit/graphql/mutations/test_resource_manager.py
+++ b/backend/tests/unit/graphql/mutations/test_resource_manager.py
@@ -8,9 +8,9 @@
from infrahub.core.node.resource_manager.ip_address_pool import CoreIPAddressPool
from infrahub.core.node.resource_manager.ip_prefix_pool import CoreIPPrefixPool
from infrahub.core.schema import SchemaRoot
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from tests.helpers.schema import TICKET, load_schema
diff --git a/backend/tests/unit/graphql/mutations/test_schema.py b/backend/tests/unit/graphql/mutations/test_schema.py
index 8768a836f6..daeffb8219 100644
--- a/backend/tests/unit/graphql/mutations/test_schema.py
+++ b/backend/tests/unit/graphql/mutations/test_schema.py
@@ -4,7 +4,7 @@
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
from infrahub.exceptions import ValidationError
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.graphql.mutations.schema import validate_kind, validate_kind_dropdown, validate_kind_enum
diff --git a/backend/tests/unit/graphql/mutations/test_task.py b/backend/tests/unit/graphql/mutations/test_task.py
index fdb3d116f5..858c169ddd 100644
--- a/backend/tests/unit/graphql/mutations/test_task.py
+++ b/backend/tests/unit/graphql/mutations/test_task.py
@@ -2,7 +2,7 @@
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
CREATE_TASK = """
mutation CreateTask(
diff --git a/backend/tests/unit/graphql/mutations/test_update_generic.py b/backend/tests/unit/graphql/mutations/test_update_generic.py
index 54eeefe2b5..e2a9b2d1f9 100644
--- a/backend/tests/unit/graphql/mutations/test_update_generic.py
+++ b/backend/tests/unit/graphql/mutations/test_update_generic.py
@@ -3,7 +3,7 @@
from infrahub.core.branch import Branch
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_display_label_generic(db: InfrahubDatabase, animal_person_schema, branch: Branch):
diff --git a/backend/tests/unit/graphql/profiles/test_mutation_create.py b/backend/tests/unit/graphql/profiles/test_mutation_create.py
index 8e936d7949..d128f8870e 100644
--- a/backend/tests/unit/graphql/profiles/test_mutation_create.py
+++ b/backend/tests/unit/graphql/profiles/test_mutation_create.py
@@ -2,7 +2,7 @@
from infrahub.core.manager import NodeManager
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_create_profile(db: InfrahubDatabase, default_branch, car_person_schema):
diff --git a/backend/tests/unit/graphql/profiles/test_query.py b/backend/tests/unit/graphql/profiles/test_query.py
index 5e7b9b49ce..4e0a4bc700 100644
--- a/backend/tests/unit/graphql/profiles/test_query.py
+++ b/backend/tests/unit/graphql/profiles/test_query.py
@@ -9,7 +9,7 @@
from infrahub.core.schema import NodeSchema
from infrahub.core.schema.generic_schema import GenericSchema
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
@pytest.fixture
diff --git a/backend/tests/unit/graphql/queries/test_branch.py b/backend/tests/unit/graphql/queries/test_branch.py
index 0d31fcd2f1..bf7bc3eea0 100644
--- a/backend/tests/unit/graphql/queries/test_branch.py
+++ b/backend/tests/unit/graphql/queries/test_branch.py
@@ -4,7 +4,7 @@
from infrahub.core.branch import Branch
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_branch_query(db: InfrahubDatabase, default_branch: Branch, register_core_models_schema, session_admin):
diff --git a/backend/tests/unit/graphql/queries/test_ipam.py b/backend/tests/unit/graphql/queries/test_ipam.py
index b203c72442..e54bb4c000 100644
--- a/backend/tests/unit/graphql/queries/test_ipam.py
+++ b/backend/tests/unit/graphql/queries/test_ipam.py
@@ -5,9 +5,9 @@
from infrahub.core.branch import Branch
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
@pytest.fixture
diff --git a/backend/tests/unit/graphql/queries/test_list_permissions.py b/backend/tests/unit/graphql/queries/test_list_permissions.py
new file mode 100644
index 0000000000..d309a744c4
--- /dev/null
+++ b/backend/tests/unit/graphql/queries/test_list_permissions.py
@@ -0,0 +1,240 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from uuid import uuid4
+
+from graphql import graphql
+
+from infrahub.auth import AccountSession, AuthType
+from infrahub.core.account import ObjectPermission
+from infrahub.core.constants import (
+ InfrahubKind,
+ PermissionAction,
+ PermissionDecision,
+)
+from infrahub.core.initialization import create_branch
+from infrahub.core.node import Node
+from infrahub.core.registry import registry
+from infrahub.graphql.initialization import prepare_graphql_params
+from infrahub.permissions.local_backend import LocalPermissionBackend
+
+if TYPE_CHECKING:
+ from infrahub.core.branch import Branch
+ from infrahub.core.protocols import CoreAccount
+ from infrahub.database import InfrahubDatabase
+ from tests.unit.graphql.conftest import PermissionsHelper
+
+
+QUERY_TAGS = """
+query {
+ BuiltinTag {
+ permissions {
+ count
+ edges {
+ node {
+ kind
+ create
+ update
+ delete
+ view
+ }
+ }
+ }
+ }
+}
+"""
+
+REPOSITORY_QUERY = """
+query {
+ CoreGenericRepository {
+ permissions {
+ count
+ edges {
+ node {
+ kind
+ create
+ update
+ delete
+ view
+ }
+ }
+ }
+ }
+}
+"""
+
+
+class TestObjectPermissions:
+ async def test_setup(
+ self,
+ db: InfrahubDatabase,
+ register_core_models_schema: None,
+ default_branch: Branch,
+ permissions_helper: PermissionsHelper,
+ first_account: CoreAccount,
+ ):
+ permissions_helper._first = first_account
+ permissions_helper._default_branch = default_branch
+ registry.permission_backends = [LocalPermissionBackend()]
+
+ permissions = []
+ for object_permission in [
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="Builtin",
+ name="*",
+ action=PermissionAction.VIEW.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="Builtin",
+ name="*",
+ action=PermissionAction.ADD.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="Builtin",
+ name="*",
+ action=PermissionAction.DELETE.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="Core",
+ name="*",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ]:
+ obj = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
+ await obj.new(
+ db=db,
+ branch=object_permission.branch,
+ namespace=object_permission.namespace,
+ name=object_permission.name,
+ action=object_permission.action,
+ decision=object_permission.decision,
+ )
+ await obj.save(db=db)
+ permissions.append(obj)
+
+ role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role.new(db=db, name="admin", permissions=permissions)
+ await role.save(db=db)
+
+ group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group.new(db=db, name="admin", roles=[role])
+ await group.save(db=db)
+
+ await group.members.add(db=db, data={"id": first_account.id})
+ await group.members.save(db=db)
+
+ async def test_first_account_tags_main_branch(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ) -> None:
+ """In the main branch the first account doesn't have the permission to make changes"""
+ session = AccountSession(
+ authenticated=True,
+ account_id=permissions_helper.first.id,
+ session_id=str(uuid4()),
+ auth_type=AuthType.JWT,
+ )
+ gql_params = prepare_graphql_params(
+ db=db, include_mutation=True, branch=permissions_helper.default_branch, account_session=session
+ )
+
+ result = await graphql(
+ schema=gql_params.schema,
+ source=QUERY_TAGS,
+ context_value=gql_params.context,
+ )
+
+ assert not result.errors
+ assert result.data
+ assert result.data["BuiltinTag"]["permissions"]["count"] == 1
+ assert result.data["BuiltinTag"]["permissions"]["edges"][0] == {
+ "node": {"kind": "BuiltinTag", "create": "DENY", "update": "DENY", "delete": "DENY", "view": "ALLOW"}
+ }
+
+ async def test_first_account_tags_non_main_branch(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ) -> None:
+ """In other branches the permissions for the first account is less restrictive"""
+ branch2 = await create_branch(branch_name="pr-12345", db=db)
+ session = AccountSession(
+ authenticated=True,
+ account_id=permissions_helper.first.id,
+ session_id=str(uuid4()),
+ auth_type=AuthType.JWT,
+ )
+ gql_params = prepare_graphql_params(db=db, include_mutation=True, branch=branch2, account_session=session)
+
+ result = await graphql(
+ schema=gql_params.schema,
+ source=QUERY_TAGS,
+ context_value=gql_params.context,
+ )
+
+ assert not result.errors
+ assert result.data
+ assert result.data["BuiltinTag"]["permissions"]["count"] == 1
+ assert result.data["BuiltinTag"]["permissions"]["edges"][0] == {
+ "node": {"kind": "BuiltinTag", "create": "ALLOW", "update": "DENY", "delete": "ALLOW", "view": "ALLOW"}
+ }
+
+ async def test_first_account_list_permissions_for_generics(
+ self, db: InfrahubDatabase, permissions_helper: PermissionsHelper
+ ) -> None:
+ """In the main branch the first account doesn't have the permission to make changes"""
+ session = AccountSession(
+ authenticated=True,
+ account_id=permissions_helper.first.id,
+ session_id=str(uuid4()),
+ auth_type=AuthType.JWT,
+ )
+ gql_params = prepare_graphql_params(
+ db=db, include_mutation=True, branch=permissions_helper.default_branch, account_session=session
+ )
+
+ result = await graphql(
+ schema=gql_params.schema,
+ source=REPOSITORY_QUERY,
+ context_value=gql_params.context,
+ )
+
+ assert not result.errors
+ assert result.data
+ assert result.data["CoreGenericRepository"]["permissions"]["count"] == 3
+ assert {
+ "node": {
+ "kind": "CoreGenericRepository",
+ "create": "DENY",
+ "update": "DENY",
+ "delete": "DENY",
+ "view": "ALLOW",
+ }
+ } in result.data["CoreGenericRepository"]["permissions"]["edges"]
+ assert {
+ "node": {
+ "kind": "CoreRepository",
+ "create": "DENY",
+ "update": "DENY",
+ "delete": "DENY",
+ "view": "ALLOW",
+ }
+ } in result.data["CoreGenericRepository"]["permissions"]["edges"]
+ assert {
+ "node": {
+ "kind": "CoreReadOnlyRepository",
+ "create": "DENY",
+ "update": "DENY",
+ "delete": "DENY",
+ "view": "ALLOW",
+ }
+ } in result.data["CoreGenericRepository"]["permissions"]["edges"]
diff --git a/backend/tests/unit/graphql/queries/test_relationship.py b/backend/tests/unit/graphql/queries/test_relationship.py
index 8196772027..0b6f9e1273 100644
--- a/backend/tests/unit/graphql/queries/test_relationship.py
+++ b/backend/tests/unit/graphql/queries/test_relationship.py
@@ -2,7 +2,7 @@
from infrahub.core.branch import Branch
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_relationship(
diff --git a/backend/tests/unit/graphql/queries/test_resource_pool.py b/backend/tests/unit/graphql/queries/test_resource_pool.py
index d1458314c0..82a398c295 100644
--- a/backend/tests/unit/graphql/queries/test_resource_pool.py
+++ b/backend/tests/unit/graphql/queries/test_resource_pool.py
@@ -10,9 +10,9 @@
from infrahub.core.node.resource_manager.ip_address_pool import CoreIPAddressPool
from infrahub.core.node.resource_manager.ip_prefix_pool import CoreIPPrefixPool
from infrahub.core.schema import SchemaRoot
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from tests.helpers.schema import TICKET, load_schema
diff --git a/backend/tests/unit/graphql/queries/test_search.py b/backend/tests/unit/graphql/queries/test_search.py
index 48124788cd..844dd56966 100644
--- a/backend/tests/unit/graphql/queries/test_search.py
+++ b/backend/tests/unit/graphql/queries/test_search.py
@@ -3,7 +3,7 @@
from infrahub.core.branch import Branch
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
SEARCH_QUERY = """
query ($search: String!) {
diff --git a/backend/tests/unit/graphql/queries/test_task.py b/backend/tests/unit/graphql/queries/test_task.py
index b302835fc9..e76575b2e1 100644
--- a/backend/tests/unit/graphql/queries/test_task.py
+++ b/backend/tests/unit/graphql/queries/test_task.py
@@ -7,7 +7,7 @@
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
CREATE_TASK = """
mutation CreateTask(
diff --git a/backend/tests/unit/graphql/test_app.py b/backend/tests/unit/graphql/test_app.py
index a7557b095a..5c5b78a3d8 100644
--- a/backend/tests/unit/graphql/test_app.py
+++ b/backend/tests/unit/graphql/test_app.py
@@ -1,3 +1,4 @@
+import pytest
from fastapi.testclient import TestClient
from infrahub.core.branch import Branch
@@ -6,7 +7,15 @@
from infrahub.database import InfrahubDatabase
-async def test_websocket(db: InfrahubDatabase, default_branch: Branch, register_core_models_schema):
+@pytest.fixture
+def client(nats, redis):
+ # In order to mock some methods later we can't load app by default because it will automatically load all import in main.py as well
+ from infrahub.server import app
+
+ return TestClient(app)
+
+
+async def test_websocket(db: InfrahubDatabase, client: TestClient, default_branch: Branch, register_core_models_schema):
t2 = await Node.init(db=db, schema=InfrahubKind.TAG, branch=default_branch)
await t2.new(db=db, name="Red", description="The Red tag")
await t2.save(db=db)
@@ -15,10 +24,6 @@ async def test_websocket(db: InfrahubDatabase, default_branch: Branch, register_
await q1.new(db=db, name="query01", query="query { BuiltinTag { count }}")
await q1.save(db=db)
- from infrahub.server import app
-
- client = TestClient(app)
-
with client:
with client.websocket_connect("/graphql") as websocket:
websocket.send_json(
diff --git a/backend/tests/unit/graphql/test_core_account.py b/backend/tests/unit/graphql/test_core_account.py
new file mode 100644
index 0000000000..b48d485d43
--- /dev/null
+++ b/backend/tests/unit/graphql/test_core_account.py
@@ -0,0 +1,124 @@
+import bcrypt
+import pytest
+from graphql import graphql
+
+from infrahub.auth import AccountSession, AuthType
+from infrahub.core.account import GlobalPermission, ObjectPermission
+from infrahub.core.branch import Branch
+from infrahub.core.constants import AccountRole, GlobalPermissions, PermissionAction, PermissionDecision
+from infrahub.core.manager import NodeManager
+from infrahub.database import InfrahubDatabase
+from infrahub.graphql.initialization import prepare_graphql_params
+
+
+@pytest.mark.parametrize("role", [e.value for e in AccountRole])
+async def test_everyone_can_update_password(db: InfrahubDatabase, default_branch: Branch, first_account, role):
+ new_password = "NewP@ssw0rd"
+ new_description = "what a cool description"
+ query = """
+ mutation {
+ InfrahubAccountSelfUpdate(data: {password: "%s", description: "%s"}) {
+ ok
+ }
+ }
+ """ % (new_password, new_description)
+
+ gql_params = prepare_graphql_params(
+ db=db,
+ include_subscription=False,
+ branch=default_branch,
+ account_session=AccountSession(
+ authenticated=True, account_id=first_account.id, role=role, auth_type=AuthType.JWT
+ ),
+ )
+
+ result = await graphql(
+ schema=gql_params.schema,
+ source=query,
+ context_value=gql_params.context,
+ root_value=None,
+ variable_values={},
+ )
+
+ assert result.errors is None
+ assert result.data["InfrahubAccountSelfUpdate"]["ok"] is True
+
+ updated_account = await NodeManager.get_one(db=db, id=first_account.id, branch=default_branch)
+ assert bcrypt.checkpw(new_password.encode("UTF-8"), updated_account.password.value.encode("UTF-8"))
+ assert updated_account.description.value == new_description
+
+
+async def test_permissions(
+ db: InfrahubDatabase, default_branch: Branch, authentication_base, session_admin, first_account
+):
+ query = """
+ query {
+ InfrahubPermissions {
+ global_permissions {
+ edges {
+ node {
+ identifier
+ }
+ }
+ }
+ object_permissions {
+ edges {
+ node {
+ identifier
+ }
+ }
+ }
+ }
+ }
+ """
+
+ gql_params = prepare_graphql_params(
+ db=db, include_subscription=False, branch=default_branch, account_session=session_admin
+ )
+
+ result = await graphql(
+ schema=gql_params.schema, source=query, context_value=gql_params.context, root_value=None, variable_values={}
+ )
+
+ assert result.errors is None
+ perms = [edge["node"]["identifier"] for edge in result.data["InfrahubPermissions"]["global_permissions"]["edges"]]
+ assert perms == [
+ str(
+ GlobalPermission(
+ id="",
+ name=GlobalPermissions.SUPER_ADMIN.value,
+ action=GlobalPermissions.SUPER_ADMIN.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ )
+ ]
+
+ perms = [edge["node"]["identifier"] for edge in result.data["InfrahubPermissions"]["object_permissions"]["edges"]]
+ assert perms == [
+ str(
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="*",
+ name="*",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ )
+ ]
+
+ gql_params = prepare_graphql_params(
+ db=db,
+ include_subscription=False,
+ branch=default_branch,
+ account_session=AccountSession(
+ authenticated=True, account_id=first_account.id, role=first_account.role.value, auth_type=AuthType.JWT
+ ),
+ )
+
+ result = await graphql(
+ schema=gql_params.schema, source=query, context_value=gql_params.context, root_value=None, variable_values={}
+ )
+
+ assert result.errors is None
+ assert not result.data["InfrahubPermissions"]["global_permissions"]["edges"]
diff --git a/backend/tests/unit/graphql/test_core_account_self_update.py b/backend/tests/unit/graphql/test_core_account_self_update.py
deleted file mode 100644
index 8b903c880a..0000000000
--- a/backend/tests/unit/graphql/test_core_account_self_update.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import bcrypt
-import pytest
-from graphql import graphql
-
-from infrahub.auth import AccountSession, AuthType
-from infrahub.core.branch import Branch
-from infrahub.core.constants import AccountRole
-from infrahub.core.manager import NodeManager
-from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
-
-
-@pytest.mark.parametrize("role", [e.value for e in AccountRole])
-async def test_everyone_can_update_password(db: InfrahubDatabase, default_branch: Branch, first_account, role):
- new_password = "NewP@ssw0rd"
- new_description = "what a cool description"
- query = """
- mutation {
- InfrahubAccountSelfUpdate(data: {password: "%s", description: "%s"}) {
- ok
- }
- }
- """ % (new_password, new_description)
-
- gql_params = prepare_graphql_params(
- db=db,
- include_subscription=False,
- branch=default_branch,
- account_session=AccountSession(
- authenticated=True, account_id=first_account.id, role=role, auth_type=AuthType.JWT
- ),
- )
-
- result = await graphql(
- schema=gql_params.schema,
- source=query,
- context_value=gql_params.context,
- root_value=None,
- variable_values={},
- )
-
- assert result.errors is None
- assert result.data["InfrahubAccountSelfUpdate"]["ok"] is True
-
- updated_account = await NodeManager.get_one(db=db, id=first_account.id, branch=default_branch)
- assert bcrypt.checkpw(new_password.encode("UTF-8"), updated_account.password.value.encode("UTF-8"))
- assert updated_account.description.value == new_description
diff --git a/backend/tests/unit/graphql/test_diff_tree_query.py b/backend/tests/unit/graphql/test_diff_tree_query.py
index b8159b38f9..fd861efeb8 100644
--- a/backend/tests/unit/graphql/test_diff_tree_query.py
+++ b/backend/tests/unit/graphql/test_diff_tree_query.py
@@ -14,12 +14,12 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.core.schema import NodeSchema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.timestamp import Timestamp
from infrahub.database import InfrahubDatabase
from infrahub.dependencies.registry import get_component_registry
-from infrahub.graphql import prepare_graphql_params
from infrahub.graphql.enums import ConflictSelection as GraphQLConfictSelection
+from infrahub.graphql.initialization import prepare_graphql_params
ADDED_ACTION = "ADDED"
UPDATED_ACTION = "UPDATED"
diff --git a/backend/tests/unit/graphql/test_graphql_query.py b/backend/tests/unit/graphql/test_graphql_query.py
index f33cfb9713..9ece69ad92 100644
--- a/backend/tests/unit/graphql/test_graphql_query.py
+++ b/backend/tests/unit/graphql/test_graphql_query.py
@@ -12,10 +12,10 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.core.schema import NodeSchema
-from infrahub.core.schema_manager import SchemaBranch
+from infrahub.core.schema.schema_branch import SchemaBranch
from infrahub.core.timestamp import Timestamp
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_info_query(db: InfrahubDatabase, default_branch: Branch, criticality_schema: NodeSchema):
diff --git a/backend/tests/unit/graphql/test_graphql_utils.py b/backend/tests/unit/graphql/test_graphql_utils.py
index 11ad5f7b4d..a30ae10d01 100644
--- a/backend/tests/unit/graphql/test_graphql_utils.py
+++ b/backend/tests/unit/graphql/test_graphql_utils.py
@@ -4,8 +4,8 @@
from infrahub.core.branch import Branch
from infrahub.core.constants import InfrahubKind
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import generate_graphql_schema
from infrahub.graphql.analyzer import extract_schema_models
+from infrahub.graphql.initialization import generate_graphql_schema
async def test_schema_models(db: InfrahubDatabase, default_branch: Branch, car_person_schema_generics, query_01: str):
@@ -38,6 +38,7 @@ async def test_schema_models_generics(
InfrahubKind.GRAPHQLQUERYGROUP,
InfrahubKind.GENERICGROUP,
InfrahubKind.STANDARDGROUP,
+ InfrahubKind.ACCOUNTGROUP,
"EdgedTestPerson",
"NestedEdgedCoreGroup",
"NestedEdgedTestCar",
diff --git a/backend/tests/unit/graphql/test_mutation_artifact_definition.py b/backend/tests/unit/graphql/test_mutation_artifact_definition.py
index 25b07d8779..f9318415fd 100644
--- a/backend/tests/unit/graphql/test_mutation_artifact_definition.py
+++ b/backend/tests/unit/graphql/test_mutation_artifact_definition.py
@@ -8,7 +8,7 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from infrahub.message_bus import messages
from infrahub.services import InfrahubServices
from tests.adapters.message_bus import BusRecorder
diff --git a/backend/tests/unit/graphql/test_mutation_create.py b/backend/tests/unit/graphql/test_mutation_create.py
index 1d1b1958d6..958ba0c4c0 100644
--- a/backend/tests/unit/graphql/test_mutation_create.py
+++ b/backend/tests/unit/graphql/test_mutation_create.py
@@ -8,7 +8,7 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_create_simple_object(db: InfrahubDatabase, default_branch, car_person_schema):
diff --git a/backend/tests/unit/graphql/test_mutation_delete.py b/backend/tests/unit/graphql/test_mutation_delete.py
index 59063bc2bd..0c5769b7be 100644
--- a/backend/tests/unit/graphql/test_mutation_delete.py
+++ b/backend/tests/unit/graphql/test_mutation_delete.py
@@ -3,7 +3,7 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_delete_object(db: InfrahubDatabase, default_branch, car_person_schema):
diff --git a/backend/tests/unit/graphql/test_mutation_graphqlquery.py b/backend/tests/unit/graphql/test_mutation_graphqlquery.py
index f45c4e5900..a7831378e5 100644
--- a/backend/tests/unit/graphql/test_mutation_graphqlquery.py
+++ b/backend/tests/unit/graphql/test_mutation_graphqlquery.py
@@ -4,7 +4,7 @@
from infrahub.core.constants import InfrahubKind
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_create_query_no_vars(db: InfrahubDatabase, default_branch, register_core_models_schema):
diff --git a/backend/tests/unit/graphql/test_mutation_relationship.py b/backend/tests/unit/graphql/test_mutation_relationship.py
index 7b7f4b7b4f..eed5daa260 100644
--- a/backend/tests/unit/graphql/test_mutation_relationship.py
+++ b/backend/tests/unit/graphql/test_mutation_relationship.py
@@ -7,7 +7,7 @@
from infrahub.core.node import Node
from infrahub.core.utils import count_relationships
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_relationship_add(
diff --git a/backend/tests/unit/graphql/test_mutation_update.py b/backend/tests/unit/graphql/test_mutation_update.py
index 2abdf97645..ed266fa7c2 100644
--- a/backend/tests/unit/graphql/test_mutation_update.py
+++ b/backend/tests/unit/graphql/test_mutation_update.py
@@ -7,7 +7,7 @@
from infrahub.core.manager import NodeManager
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_update_simple_object(db: InfrahubDatabase, person_john_main: Node, branch: Branch):
diff --git a/backend/tests/unit/graphql/test_mutation_upsert.py b/backend/tests/unit/graphql/test_mutation_upsert.py
index 7156a91213..e51e394fd9 100644
--- a/backend/tests/unit/graphql/test_mutation_upsert.py
+++ b/backend/tests/unit/graphql/test_mutation_upsert.py
@@ -8,7 +8,7 @@
from infrahub.core.registry import registry
from infrahub.core.schema import SchemaRoot
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
from tests.constants import TestKind
from tests.helpers.schema import TICKET
diff --git a/backend/tests/unit/graphql/test_parser.py b/backend/tests/unit/graphql/test_parser.py
index e5df6f8ac3..a29c357f0f 100644
--- a/backend/tests/unit/graphql/test_parser.py
+++ b/backend/tests/unit/graphql/test_parser.py
@@ -3,7 +3,7 @@
from infrahub.core.branch import Branch
from infrahub.core.node import Node
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_simple_directive(db: InfrahubDatabase, default_branch: Branch, criticality_schema):
diff --git a/backend/tests/unit/graphql/test_query_analyzer.py b/backend/tests/unit/graphql/test_query_analyzer.py
index 9adbbe6ca6..3323c84204 100644
--- a/backend/tests/unit/graphql/test_query_analyzer.py
+++ b/backend/tests/unit/graphql/test_query_analyzer.py
@@ -3,8 +3,8 @@
from infrahub.core.branch import Branch
from infrahub.core.constants import InfrahubKind
from infrahub.database import InfrahubDatabase
-from infrahub.graphql import prepare_graphql_params
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
+from infrahub.graphql.initialization import prepare_graphql_params
async def test_analyzer_init_with_schema(
@@ -98,6 +98,7 @@ async def test_get_models_in_use(
InfrahubKind.GRAPHQLQUERYGROUP,
InfrahubKind.GENERICGROUP,
InfrahubKind.STANDARDGROUP,
+ InfrahubKind.ACCOUNTGROUP,
"TestCar",
"TestElectricCar",
"TestGazCar",
diff --git a/sync/examples/nautobot-v2_to_infrahub/infrahub/__init__.py b/backend/tests/unit/menu/__init__.py
similarity index 100%
rename from sync/examples/nautobot-v2_to_infrahub/infrahub/__init__.py
rename to backend/tests/unit/menu/__init__.py
diff --git a/backend/tests/unit/menu/test_generator.py b/backend/tests/unit/menu/test_generator.py
new file mode 100644
index 0000000000..1781ae4c02
--- /dev/null
+++ b/backend/tests/unit/menu/test_generator.py
@@ -0,0 +1,46 @@
+from infrahub.core import registry
+from infrahub.core.branch import Branch
+from infrahub.core.initialization import create_default_menu
+from infrahub.core.protocols import CoreMenuItem
+from infrahub.core.schema import SchemaRoot
+from infrahub.database import InfrahubDatabase
+from infrahub.menu.constants import MenuSection
+from infrahub.menu.generator import generate_menu
+from infrahub.menu.models import MenuItemDefinition
+
+
+async def test_generate_menu(
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ car_person_schema_generics: SchemaRoot,
+):
+ schema_branch = registry.schema.get_schema_branch(name=default_branch.name)
+
+ schema_electriccar = schema_branch.get(name="TestElectricCar")
+ schema_electriccar.menu_placement = "Builtin:ObjectManagement"
+ schema_branch.set(name="TestElectricCar", schema=schema_electriccar)
+
+ await create_default_menu(db=db)
+
+ new_menu_items = [
+ MenuItemDefinition(
+ namespace="Test",
+ name="CarGaz",
+ label="Car Gaz",
+ kind="TestCarGaz",
+ section=MenuSection.OBJECT,
+ order_weight=1500,
+ )
+ ]
+
+ for item in new_menu_items:
+ obj = await item.to_node(db=db)
+ await obj.save(db=db)
+
+ menu_items = await registry.manager.query(
+ db=db, schema=CoreMenuItem, branch=default_branch, prefetch_relationships=True
+ )
+ menu = await generate_menu(db=db, branch=default_branch, menu_items=menu_items)
+
+ assert menu
+ assert "Test:CarGaz" in menu.data.keys()
diff --git a/backend/tests/unit/message_bus/operations/requests/test_graphql_query_group.py b/backend/tests/unit/message_bus/operations/requests/test_graphql_query_group.py
index abbdc32c3b..b3045a2293 100644
--- a/backend/tests/unit/message_bus/operations/requests/test_graphql_query_group.py
+++ b/backend/tests/unit/message_bus/operations/requests/test_graphql_query_group.py
@@ -63,4 +63,4 @@ async def test_graphql_group_update(db: InfrahubDatabase, httpx_mock: HTTPXMock,
match_headers={"X-Infrahub-Tracker": "mutation-relationshipadd"},
)
- await update(message=message, service=service)
+ await update.fn(message=message, service=service)
diff --git a/backend/tests/unit/message_bus/operations/requests/test_proposed_change.py b/backend/tests/unit/message_bus/operations/requests/test_proposed_change.py
index bfa8a00adc..cb8c6c6371 100644
--- a/backend/tests/unit/message_bus/operations/requests/test_proposed_change.py
+++ b/backend/tests/unit/message_bus/operations/requests/test_proposed_change.py
@@ -128,8 +128,8 @@ async def test_get_proposed_change_schema_integrity_constraints(
)
non_generate_profile_constraints = [c for c in constraints if c.constraint_name != "node.generate_profile.update"]
# should be updated/removed when ConstraintValidatorDeterminer is updated (#2592)
- assert len(constraints) == 159
- assert len(non_generate_profile_constraints) == 94
+ assert len(constraints) == 181
+ assert len(non_generate_profile_constraints) == 109
dumped_constraints = [c.model_dump() for c in non_generate_profile_constraints]
assert {
"constraint_name": "relationship.optional.update",
@@ -288,8 +288,8 @@ async def test_schema_integrity(
branch2_schema.set(name="TestPerson", schema=person_schema)
# Ignore creation of Task Report response
- httpx_mock.add_response(method="POST", url="http://mock/graphql", json={"data": {}})
- await proposed_change.schema_integrity(message=schema_integrity_01, service=service_all)
+ httpx_mock.add_response(method="POST", url="http://mock/graphql/main", json={"data": {}})
+ await proposed_change.schema_integrity.fn(message=schema_integrity_01, service=service_all)
checks = await registry.manager.query(db=db, schema=InfrahubKind.SCHEMACHECK)
assert len(checks) == 1
diff --git a/backend/tests/unit/message_bus/test_mappings.py b/backend/tests/unit/message_bus/test_mappings.py
index ffae6c3ce4..7624b3ba7b 100644
--- a/backend/tests/unit/message_bus/test_mappings.py
+++ b/backend/tests/unit/message_bus/test_mappings.py
@@ -1,3 +1,10 @@
+from __future__ import annotations
+
+from typing import Callable
+
+import pytest
+from prefect import Flow
+
from infrahub.message_bus.messages import MESSAGE_MAP
from infrahub.message_bus.operations import COMMAND_MAP
@@ -7,3 +14,14 @@ def test_message_command_overlap():
messages = sorted(list(MESSAGE_MAP.keys()))
commands = sorted(list(COMMAND_MAP.keys()))
assert messages == commands
+
+
+@pytest.mark.parametrize(
+ "operation",
+ [pytest.param(function, id=key) for key, function in COMMAND_MAP.items() if not key.startswith("refresh.registry")],
+)
+def test_operations_decorated(operation: Callable):
+ if callable(operation) and hasattr(operation, "__name__") and "Flow" not in type(operation).__name__:
+ pytest.fail(f"{operation.__name__} is not decorated with @flow")
+ else:
+ assert isinstance(operation, Flow), f"{operation.__name__} is not a valid Prefect flow"
diff --git a/sync/examples/nautobot-v2_to_infrahub/nautobot/__init__.py b/backend/tests/unit/permissions/__init__.py
similarity index 100%
rename from sync/examples/nautobot-v2_to_infrahub/nautobot/__init__.py
rename to backend/tests/unit/permissions/__init__.py
diff --git a/backend/tests/unit/permissions/test_backends.py b/backend/tests/unit/permissions/test_backends.py
new file mode 100644
index 0000000000..ac8dde385f
--- /dev/null
+++ b/backend/tests/unit/permissions/test_backends.py
@@ -0,0 +1,205 @@
+from infrahub.core.account import GlobalPermission, ObjectPermission
+from infrahub.core.branch import Branch
+from infrahub.core.constants import GlobalPermissions, InfrahubKind, PermissionAction, PermissionDecision
+from infrahub.core.node import Node
+from infrahub.core.protocols import CoreAccount
+from infrahub.database import InfrahubDatabase
+from infrahub.permissions import LocalPermissionBackend
+
+
+async def test_load_permissions(db: InfrahubDatabase, default_branch: Branch, create_test_admin, first_account):
+ backend = LocalPermissionBackend()
+
+ permissions = await backend.load_permissions(db=db, account_id=create_test_admin.id, branch=default_branch)
+
+ assert "global_permissions" in permissions
+ assert permissions["global_permissions"][0].action == GlobalPermissions.SUPER_ADMIN.value
+
+ assert "object_permissions" in permissions
+ assert str(permissions["object_permissions"][0]) == str(
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="*",
+ name="*",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ )
+
+ permissions = await backend.load_permissions(db=db, account_id=first_account.id, branch=default_branch)
+
+ assert "global_permissions" in permissions
+ assert not permissions["global_permissions"]
+
+ assert "object_permissions" in permissions
+ assert not permissions["object_permissions"]
+
+
+async def test_has_permission_global(
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ register_core_models_schema: None,
+ create_test_admin: CoreAccount,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+):
+ backend = LocalPermissionBackend()
+
+ allow_default_branch_edition = GlobalPermission(
+ id="",
+ action=GlobalPermissions.EDIT_DEFAULT_BRANCH.value,
+ decision=PermissionDecision.ALLOW.value,
+ name="Edit default branch",
+ )
+
+ role1_permissions = []
+ obj = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await obj.new(
+ db=db,
+ name=allow_default_branch_edition.name,
+ action=allow_default_branch_edition.action,
+ decision=allow_default_branch_edition.decision,
+ )
+ await obj.save(db=db)
+ role1_permissions.append(obj)
+
+ role1 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role1.new(db=db, name="anything but tags", permissions=role1_permissions)
+ await role1.save(db=db)
+
+ group1 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group1.new(db=db, name="group1", roles=[role1])
+ await group1.save(db=db)
+
+ await group1.members.add(db=db, data={"id": first_account.id})
+ await group1.members.save(db=db)
+
+ role2_permissions = []
+ for p in [
+ allow_default_branch_edition,
+ GlobalPermission(
+ id="",
+ action=GlobalPermissions.EDIT_DEFAULT_BRANCH.value,
+ decision=PermissionDecision.DENY.value,
+ name="Edit default branch",
+ ),
+ ]:
+ obj = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
+ await obj.new(db=db, name=p.name, action=p.action, decision=p.decision)
+ await obj.save(db=db)
+ role2_permissions.append(obj)
+
+ role2 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role2.new(db=db, name="only tags", permissions=role2_permissions)
+ await role2.save(db=db)
+
+ group2 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group2.new(db=db, name="group2", roles=[role2])
+ await group2.save(db=db)
+
+ await group2.members.add(db=db, data={"id": second_account.id})
+ await group2.members.save(db=db)
+
+ assert await backend.has_permission(
+ db=db, account_id=first_account.id, permission=str(allow_default_branch_edition), branch=default_branch
+ )
+ assert not await backend.has_permission(
+ db=db, account_id=second_account.id, permission=str(allow_default_branch_edition), branch=default_branch
+ )
+
+
+async def test_has_permission_object(
+ db: InfrahubDatabase,
+ default_branch: Branch,
+ register_core_models_schema: None,
+ create_test_admin: CoreAccount,
+ first_account: CoreAccount,
+ second_account: CoreAccount,
+):
+ backend = LocalPermissionBackend()
+
+ role1_permissions = []
+ for p in [
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="*",
+ name="*",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="Builtin",
+ name="Tag",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.DENY.value,
+ ),
+ ]:
+ obj = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
+ await obj.new(db=db, branch=p.branch, namespace=p.namespace, name=p.name, action=p.action, decision=p.decision)
+ await obj.save(db=db)
+ role1_permissions.append(obj)
+
+ role1 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role1.new(db=db, name="anything but tags", permissions=role1_permissions)
+ await role1.save(db=db)
+
+ group1 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group1.new(db=db, name="group1", roles=[role1])
+ await group1.save(db=db)
+
+ await group1.members.add(db=db, data={"id": first_account.id})
+ await group1.members.save(db=db)
+
+ role2_permissions = []
+ for p in [
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="*",
+ name="*",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.DENY.value,
+ ),
+ ObjectPermission(
+ id="",
+ branch="*",
+ namespace="Builtin",
+ name="Tag",
+ action=PermissionAction.ANY.value,
+ decision=PermissionDecision.ALLOW.value,
+ ),
+ ]:
+ obj = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
+ await obj.new(db=db, branch=p.branch, namespace=p.namespace, name=p.name, action=p.action, decision=p.decision)
+ await obj.save(db=db)
+ role2_permissions.append(obj)
+
+ role2 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
+ await role2.new(db=db, name="only tags", permissions=role2_permissions)
+ await role2.save(db=db)
+
+ group2 = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
+ await group2.new(db=db, name="group2", roles=[role2])
+ await group2.save(db=db)
+
+ await group2.members.add(db=db, data={"id": second_account.id})
+ await group2.members.save(db=db)
+
+ permission = ObjectPermission(
+ id="",
+ branch="*",
+ namespace="Builtin",
+ name="Tag",
+ action=PermissionAction.ADD.value,
+ decision=PermissionDecision.ALLOW.value,
+ )
+ assert not await backend.has_permission(
+ db=db, account_id=first_account.id, permission=str(permission), branch=default_branch
+ )
+ assert await backend.has_permission(
+ db=db, account_id=second_account.id, permission=str(permission), branch=default_branch
+ )
diff --git a/backend/tests/unit/services/adapters/redis/test_redis.py b/backend/tests/unit/services/adapters/redis/test_redis.py
index a7348438f1..e2c36cca48 100644
--- a/backend/tests/unit/services/adapters/redis/test_redis.py
+++ b/backend/tests/unit/services/adapters/redis/test_redis.py
@@ -8,7 +8,7 @@
from infrahub.services.adapters.cache.redis import RedisCache
-async def test_get():
+async def test_get(redis):
if config.SETTINGS.cache.driver != config.CacheDriver.Redis:
pytest.skip("Must use Redis to run this test")
@@ -26,7 +26,7 @@ async def test_get():
assert after_expiry is None
-async def test_list_keys():
+async def test_list_keys(redis):
if config.SETTINGS.cache.driver != config.CacheDriver.Redis:
pytest.skip("Must use Redis to run this test")
diff --git a/sync/examples/netbox_to_infrahub/infrahub/__init__.py b/backend/tests/unit/workflows/__init__.py
similarity index 100%
rename from sync/examples/netbox_to_infrahub/infrahub/__init__.py
rename to backend/tests/unit/workflows/__init__.py
diff --git a/backend/tests/unit/workflows/test_catalogue.py b/backend/tests/unit/workflows/test_catalogue.py
new file mode 100644
index 0000000000..f219c442a1
--- /dev/null
+++ b/backend/tests/unit/workflows/test_catalogue.py
@@ -0,0 +1,16 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import pytest
+
+from infrahub.workflows.catalogue import workflows
+
+if TYPE_CHECKING:
+ from infrahub.workflows.models import WorkflowDefinition
+
+
+@pytest.mark.parametrize("workflow", [pytest.param(workflow, id=workflow.name) for workflow in workflows])
+def test_workflow_definition(workflow: WorkflowDefinition) -> None:
+ """Validate that we can import the function for each workflow."""
+ workflow.validate_workflow()
diff --git a/changelog/+compose-ansi.fixed.md b/changelog/+compose-ansi.fixed.md
new file mode 100644
index 0000000000..bdbe0f923a
--- /dev/null
+++ b/changelog/+compose-ansi.fixed.md
@@ -0,0 +1 @@
+Fixes an issue where docker compose would output ANSI control characters that don't support it
diff --git a/changelog/1075.fixed.md b/changelog/1075.fixed.md
new file mode 100644
index 0000000000..02ee48e323
--- /dev/null
+++ b/changelog/1075.fixed.md
@@ -0,0 +1 @@
+The `infrahub-git` agent service has been renamed to `task-worker` in docker compose and the command to start it has been updated as well
\ No newline at end of file
diff --git a/changelog/3302.added.md b/changelog/3302.added.md
new file mode 100644
index 0000000000..e7d414c329
--- /dev/null
+++ b/changelog/3302.added.md
@@ -0,0 +1 @@
+Add internal HTTP adapter to allow for generic access from Infrahub
diff --git a/changelog/3435.fixed.md b/changelog/3435.fixed.md
new file mode 100644
index 0000000000..d91c9c7382
--- /dev/null
+++ b/changelog/3435.fixed.md
@@ -0,0 +1 @@
+Add ability to import repositories with default branch other than 'main'.
diff --git a/changelog/3908.added.md b/changelog/3908.added.md
new file mode 100644
index 0000000000..8612bf2e8d
--- /dev/null
+++ b/changelog/3908.added.md
@@ -0,0 +1 @@
+Add support to search a node by human friendly ID within a GraphQL query
\ No newline at end of file
diff --git a/changelog/4062.fixed.md b/changelog/4062.fixed.md
new file mode 100644
index 0000000000..dfbbe0e503
--- /dev/null
+++ b/changelog/4062.fixed.md
@@ -0,0 +1 @@
+Allow users to run artifacts and generators on nodes without name attribute
\ No newline at end of file
diff --git a/development/Dockerfile b/development/Dockerfile
index f53f6f0486..71d8d6e99f 100644
--- a/development/Dockerfile
+++ b/development/Dockerfile
@@ -72,10 +72,12 @@ RUN git config --global user.name "Infrahub" && \
git config --global credential.usehttppath true && \
git config --global credential.helper /usr/local/bin/infrahub-git-credential
-RUN mkdir -p /opt/infrahub/git /opt/infrahub/storage /opt/infrahub/source /opt/infrahub/frontend/app/dist
+RUN mkdir -p /opt/infrahub/git /opt/infrahub/storage /opt/infrahub/source /opt/infrahub/frontend/app/dist /opt/infrahub/workflow
WORKDIR /source
+ENV PREFECT_WORKER_QUERY_SECONDS="2"
+
# --------------------------------------------
# Import Frontend Build
# --------------------------------------------
diff --git a/development/docker-compose-database-memgraph.yml b/development/docker-compose-database-memgraph.yml
index abc4bc01ee..917e585568 100644
--- a/development/docker-compose-database-memgraph.yml
+++ b/development/docker-compose-database-memgraph.yml
@@ -1,6 +1,7 @@
---
services:
database:
+ profiles: [demo, dev]
image: "${DATABASE_DOCKER_IMAGE:-memgraph/memgraph-mage:latest}"
init: true
volumes:
diff --git a/development/docker-compose-database-neo4j.yml b/development/docker-compose-database-neo4j.yml
index e0ab7e00eb..b5ffcb80b0 100644
--- a/development/docker-compose-database-neo4j.yml
+++ b/development/docker-compose-database-neo4j.yml
@@ -1,6 +1,7 @@
---
services:
database:
+ profiles: [demo, dev]
image: "${DATABASE_DOCKER_IMAGE:-neo4j:enterprise}"
environment:
- "NEO4J_AUTH=neo4j/admin"
diff --git a/development/docker-compose-deps-nats.yml b/development/docker-compose-deps-nats.yml
index 947daa2ad9..c686a31694 100644
--- a/development/docker-compose-deps-nats.yml
+++ b/development/docker-compose-deps-nats.yml
@@ -2,6 +2,7 @@
# yamllint disable rule:line-length
services:
message-queue:
+ profiles: [demo, dev]
image: "${MESSAGE_QUEUE_DOCKER_IMAGE:-nats:alpine}" # need alpine since latest is based on scratch (no wget available)
volumes:
- ./nats-server.conf:/etc/nats/nats-server.conf
@@ -13,6 +14,7 @@ services:
start_period: 10s
# This is actually unused but required to not break all the other compose files requiring this service...
cache:
+ profiles: [demo, dev]
image: "${MESSAGE_QUEUE_DOCKER_IMAGE:-nats:alpine}"
healthcheck:
test: wget -O /dev/null http://localhost:8222/varz || exit 1
@@ -20,3 +22,37 @@ services:
timeout: 5s
retries: 20
start_period: 10s
+ task-manager:
+ profiles: [dev]
+ image: "${TASK_MANAGER_DOCKER_IMAGE:-prefecthq/prefect:3.0.3-python3.12}"
+ command: prefect server start --host 0.0.0.0 --ui
+ environment:
+ PREFECT_API_DATABASE_CONNECTION_URL: postgresql+asyncpg://postgres:postgres@task-manager-db:5432/prefect
+ PREFECT_LOCAL_STORAGE_PATH: ${PREFECT_LOCAL_STORAGE_PATH:-/opt/prefect/}
+ PREFECT_WORKER_QUERY_SECONDS: 3
+ PREFECT_AGENT_QUERY_INTERVAL: 3
+ healthcheck:
+ test: /usr/local/bin/httpx http://localhost:4200/api/health || exit 1
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ start_period: 10s
+ depends_on:
+ - task-manager-db
+ task-manager-db:
+ profiles: [dev]
+ image: postgres:16-alpine
+ environment:
+ - POSTGRES_USER=postgres
+ - POSTGRES_PASSWORD=postgres
+ - POSTGRES_DB=prefect
+ volumes:
+ - workflow_db:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+volumes:
+ workflow_db:
diff --git a/development/docker-compose-deps.yml b/development/docker-compose-deps.yml
index 00ed88f1ec..e19c321242 100644
--- a/development/docker-compose-deps.yml
+++ b/development/docker-compose-deps.yml
@@ -1,6 +1,7 @@
---
services:
message-queue:
+ profiles: [demo, dev]
user: rabbitmq
image: "${MESSAGE_QUEUE_DOCKER_IMAGE:-rabbitmq:latest}"
environment:
@@ -13,9 +14,42 @@ services:
retries: 10
start_period: 3s
cache:
+ profiles: [demo, dev]
image: "${CACHE_DOCKER_IMAGE:-redis:latest}"
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 5s
timeout: 5s
retries: 3
+ task-manager:
+ profiles: [dev]
+ image: "${TASK_MANAGER_DOCKER_IMAGE:-prefecthq/prefect:3.0.3-python3.12}"
+ command: prefect server start --host 0.0.0.0 --ui
+ environment:
+ PREFECT_API_DATABASE_CONNECTION_URL: postgresql+asyncpg://postgres:postgres@task-manager-db:5432/prefect
+ PREFECT_LOCAL_STORAGE_PATH: ${PREFECT_LOCAL_STORAGE_PATH:-/opt/prefect/}
+ healthcheck:
+ test: /usr/local/bin/httpx http://localhost:4200/api/health || exit 1
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ start_period: 10s
+ depends_on:
+ - task-manager-db
+ task-manager-db:
+ profiles: [dev]
+ image: postgres:16-alpine
+ environment:
+ - POSTGRES_USER=postgres
+ - POSTGRES_PASSWORD=postgres
+ - POSTGRES_DB=prefect
+ volumes:
+ - workflow_db:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+volumes:
+ workflow_db:
diff --git a/development/docker-compose-test-cache.yml b/development/docker-compose-test-cache.yml
deleted file mode 100644
index 8306345976..0000000000
--- a/development/docker-compose-test-cache.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-# yamllint disable rule:line-length
-services:
- cache:
- deploy:
- mode: replicated
- replicas: "${NBR_WORKERS}"
diff --git a/development/docker-compose-test-deps.yml b/development/docker-compose-test-deps.yml
new file mode 100644
index 0000000000..df0c6ec7b8
--- /dev/null
+++ b/development/docker-compose-test-deps.yml
@@ -0,0 +1,15 @@
+---
+# yamllint disable rule:line-length
+services:
+ cache:
+ deploy:
+ mode: replicated
+ replicas: "${NBR_WORKERS}"
+ message-queue:
+ deploy:
+ mode: replicated
+ replicas: "${NBR_WORKERS}"
+ task-manager:
+ deploy:
+ mode: replicated
+ replicas: "${NBR_WORKERS}"
diff --git a/development/docker-compose-test-scale.yml b/development/docker-compose-test-scale.yml
index cbb82c9590..4c7d7180f8 100644
--- a/development/docker-compose-test-scale.yml
+++ b/development/docker-compose-test-scale.yml
@@ -84,7 +84,7 @@ x-infrahub-config: &infrahub_config
OTEL_RESOURCE_ATTRIBUTES:
services:
- infrahub-server:
+ server:
build:
context: ../
dockerfile: development/Dockerfile
diff --git a/development/docker-compose.default.yml b/development/docker-compose.default.yml
index 02281d6fe6..5457942a84 100644
--- a/development/docker-compose.default.yml
+++ b/development/docker-compose.default.yml
@@ -1,5 +1,5 @@
---
services:
- infrahub-server:
+ server:
ports:
- "${INFRAHUB_SERVER_PORT:-8000}:8000"
diff --git a/development/docker-compose.dev-override.yml.tmp b/development/docker-compose.dev-override.yml.tmp
index 59348e84a8..6ca6ee23be 100644
--- a/development/docker-compose.dev-override.yml.tmp
+++ b/development/docker-compose.dev-override.yml.tmp
@@ -12,3 +12,6 @@ services:
cache:
ports:
- "6379:6379"
+ task-manager:
+ ports:
+ - "4200:4200"
\ No newline at end of file
diff --git a/development/docker-compose.local-build.yml b/development/docker-compose.local-build.yml
index 928bc2f6dd..f136a71abb 100644
--- a/development/docker-compose.local-build.yml
+++ b/development/docker-compose.local-build.yml
@@ -1,10 +1,11 @@
---
services:
- infrahub-server:
+ server:
volumes:
- ../:/source
- "storage_data:/opt/infrahub/storage"
- infrahub-git:
+
+ task-worker:
volumes:
- ../:/source
- "git_data:/opt/infrahub/git"
diff --git a/development/docker-compose.override.yml.tmp b/development/docker-compose.override.yml.tmp
index 0967decb3d..0e0edada6f 100644
--- a/development/docker-compose.override.yml.tmp
+++ b/development/docker-compose.override.yml.tmp
@@ -95,7 +95,7 @@ services:
# --------------------------------------------------------------------------------
# Infrahub Server
# --------------------------------------------------------------------------------
- infrahub-server:
+ server:
ports:
- "8000:8000"
diff --git a/development/docker-compose.yml b/development/docker-compose.yml
index 4f311c59c6..3080404e5a 100644
--- a/development/docker-compose.yml
+++ b/development/docker-compose.yml
@@ -92,10 +92,13 @@ x-infrahub-config: &infrahub_config
INFRAHUB_TRACE_EXPORTER_PROTOCOL:
INFRAHUB_TRACE_EXPORTER_TYPE:
INFRAHUB_TRACE_INSECURE:
+ INFRAHUB_WORKFLOW_ADDRESS:
+ INFRAHUB_WORKFLOW_PORT:
OTEL_RESOURCE_ATTRIBUTES:
services:
- infrahub-server:
+ server:
+ profiles: [demo, dev]
build:
context: ../
dockerfile: development/Dockerfile
@@ -111,6 +114,9 @@ services:
condition: service_healthy
cache:
condition: service_healthy
+ task-manager:
+ condition: service_healthy
+ required: false
environment:
<<: *infrahub_config
INFRAHUB_CONFIG: /source/development/infrahub.toml
@@ -119,8 +125,12 @@ services:
INFRAHUB_SECURITY_SECRET_KEY: 327f747f-efac-42be-9e73-999f08f86b92
INFRAHUB_BROKER_ADDRESS: message-queue
INFRAHUB_CACHE_ADDRESS: "${INFRAHUB_CACHE_ADDRESS:-cache}"
+ INFRAHUB_WORKFLOW_ADDRESS: task-manager
+ INFRAHUB_WORKFLOW_PORT: 4200
+ PREFECT_API_URL: "http://task-manager:4200/api"
volumes:
- "storage_data:/opt/infrahub/storage"
+ - "workflow_data:/opt/infrahub/workflow"
tty: true
labels:
com.github.run_id: "${GITHUB_RUN_ID:-unknown}"
@@ -132,6 +142,7 @@ services:
retries: 20
start_period: 10s
infrahub-git:
+ profiles: [demo]
deploy:
mode: replicated
replicas: 2
@@ -144,11 +155,11 @@ services:
command: infrahub git-agent start --debug
restart: unless-stopped
depends_on:
- - infrahub-server
+ - server
environment:
<<: *infrahub_config
INFRAHUB_CONFIG: /source/development/infrahub.toml
- INFRAHUB_ADDRESS: http://infrahub-server:8000
+ INFRAHUB_ADDRESS: http://server:8000
INFRAHUB_PRODUCTION: false
INFRAHUB_LOG_LEVEL: DEBUG
INFRAHUB_API_TOKEN: 06438eb2-8019-4776-878c-0941b1f1d1ec
@@ -163,7 +174,45 @@ services:
com.github.run_id: "${GITHUB_RUN_ID:-unknown}"
com.github.job: "${JOB_NAME:-unknown}"
+ task-worker:
+ profiles: [dev]
+ deploy:
+ mode: replicated
+ replicas: 2
+ build:
+ context: ../
+ dockerfile: development/Dockerfile
+ target: backend
+ image: "${IMAGE_NAME}:${IMAGE_VER}"
+ pull_policy: always
+ command: prefect worker start --type infrahubasync --pool infrahub-worker --with-healthcheck
+ restart: unless-stopped
+ depends_on:
+ - server
+ environment:
+ <<: *infrahub_config
+ INFRAHUB_CONFIG: /source/development/infrahub.toml
+ INFRAHUB_ADDRESS: http://server:8000
+ INFRAHUB_INTERNAL_ADDRESS: "http://server:8000"
+ INFRAHUB_DB_ADDRESS: "database"
+ INFRAHUB_PRODUCTION: false
+ INFRAHUB_API_TOKEN: 06438eb2-8019-4776-878c-0941b1f1d1ec
+ INFRAHUB_TIMEOUT: 20
+ INFRAHUB_BROKER_ADDRESS: message-queue
+ INFRAHUB_CACHE_ADDRESS: "${INFRAHUB_CACHE_ADDRESS:-cache}"
+ INFRAHUB_WORKFLOW_ADDRESS: "${INFRAHUB_WORKFLOW_ADDRESS:-task-manager}"
+ INFRAHUB_WORKFLOW_PORT: "${INFRAHUB_WORKFLOW_PORT:-4200}"
+ PREFECT_API_URL: "http://task-manager:4200/api"
+ volumes:
+ - "git_data:/opt/infrahub/git"
+ - "git_remote_data:/remote"
+ tty: true
+ labels:
+ com.github.run_id: "${GITHUB_RUN_ID:-unknown}"
+ com.github.job: "${JOB_NAME:-unknown}"
+
volumes:
git_data:
git_remote_data:
storage_data:
+ workflow_data:
diff --git a/development/infrahub.toml b/development/infrahub.toml
index a2024a1bac..fdc7cbe407 100644
--- a/development/infrahub.toml
+++ b/development/infrahub.toml
@@ -1,5 +1,5 @@
[main]
-internal_address = "http://infrahub-server:8000"
+internal_address = "http://server:8000"
[git]
repositories_directory = "/opt/infrahub/git"
diff --git a/development/prometheus/config.yml b/development/prometheus/config.yml
index 0c2fb6c0ff..c08f2b736d 100644
--- a/development/prometheus/config.yml
+++ b/development/prometheus/config.yml
@@ -9,8 +9,8 @@ scrape_configs:
- job_name: 'infrahub'
static_configs:
- - targets: ['infrahub-server:8000']
- - targets: ['infrahub-git:8000']
+ - targets: ['server:8000']
+ - targets: ['task-worker:8000']
- job_name: 'message-queue'
static_configs:
diff --git a/development/vmagent.yml b/development/vmagent.yml
index c09179cf08..c8dd0ddf38 100644
--- a/development/vmagent.yml
+++ b/development/vmagent.yml
@@ -8,5 +8,5 @@ scrape_configs:
- targets:
- "database:2004"
# - "memgraph-exporter:2004" # requires enterprise license
- - "infrahub-server:8000/metrics"
- - "infrahub-git:8000"
+ - "server:8000/metrics"
+ - "task-worker:8000"
diff --git a/docker-compose.yml b/docker-compose.yml
index cd8afa3169..09fc28786d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -126,7 +126,7 @@ services:
retries: 3
database:
- image: ${NEO4J_DOCKER_IMAGE:-neo4j:5.19.0-community}
+ image: ${NEO4J_DOCKER_IMAGE:-neo4j:5.20.0-community}
restart: unless-stopped
environment:
NEO4J_AUTH: neo4j/${INFRAHUB_DB_PASSWORD:-admin}
@@ -145,8 +145,40 @@ services:
- 2004:2004
- 6362:6362
+ task-manager:
+ image: "${TASK_MANAGER_DOCKER_IMAGE:-prefecthq/prefect:3.0.3-python3.12}"
+ command: prefect server start --host 0.0.0.0 --ui
+ restart: unless-stopped
+ environment:
+ PREFECT_API_DATABASE_CONNECTION_URL: postgresql+asyncpg://postgres:postgres@task-manager-db:5432/prefect
+ PREFECT_WORKER_QUERY_SECONDS: 3
+ PREFECT_AGENT_QUERY_INTERVAL: 3
+ healthcheck:
+ test: /usr/local/bin/httpx http://localhost:4200/api/health || exit 1
+ interval: 5s
+ timeout: 5s
+ retries: 20
+ start_period: 10s
+ depends_on:
+ - task-manager-db
+
+ task-manager-db:
+ image: postgres:16-alpine
+ restart: unless-stopped
+ environment:
+ - POSTGRES_USER=postgres
+ - POSTGRES_PASSWORD=postgres
+ - POSTGRES_DB=prefect
+ volumes:
+ - workflow_db:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
infrahub-server:
- image: "registry.opsmill.io/opsmill/infrahub:${VERSION:-0.16.2}"
+ image: "${INFRAHUB_DOCKER_IMAGE:-registry.opsmill.io/opsmill/infrahub}:${VERSION:-0.16.2}"
restart: unless-stopped
command: >
gunicorn --config backend/infrahub/serve/gunicorn_config.py
@@ -185,7 +217,7 @@ services:
deploy:
mode: replicated
replicas: 2
- image: "registry.opsmill.io/opsmill/infrahub:${VERSION:-0.16.2}"
+ image: "${INFRAHUB_DOCKER_IMAGE:-registry.opsmill.io/opsmill/infrahub}:${VERSION:-0.16.2}"
command: infrahub git-agent start --debug
restart: unless-stopped
depends_on:
@@ -213,3 +245,4 @@ volumes:
git_data:
git_remote_data:
storage_data:
+ workflow_db:
diff --git a/docs/docs/development/backend.mdx b/docs/docs/development/backend.mdx
index 9ba0a09faf..f32b116fb2 100644
--- a/docs/docs/development/backend.mdx
+++ b/docs/docs/development/backend.mdx
@@ -33,7 +33,6 @@ export INFRAHUB_DB_TYPE=neo4j # Accepts neo4j or memgraph
export INFRAHUB_INITIAL_ADMIN_TOKEN="${ADMIN_TOKEN}" # Random string which can be generated using: openssl rand -hex 16
export INFRAHUB_STORAGE_LOCAL_PATH="${HOME}/Development/infrahub-storage"
export INFRAHUB_API_CORS_ALLOW_ORIGINS='["http://localhost:8080"]' # Allow frontend/backend communications without CORS issues
-export INFRAHUB_IMAGE_VER=local # Force building a local image instead of pulling one from the registry
```
The exported environment variables are very important and must be set before moving to another step. Without these, you will likely face some errors or issues later.
@@ -59,7 +58,14 @@ cd infrahub # or the directory of your choice
poetry install
```
-Now it's time to bring the required services up, and for that we have demo commands:
+Some tests require some services to work. By default, they are automatically started by pytest before tests run.
+It is also possible to disable the automatic startup of services and to rely on existing services using an environment variable:
+
+```bash
+export INFRAHUB_USE_TEST_CONTAINERS=false
+```
+
+The required services now need to be started using dedicated commands:
```shell
invoke dev.destroy dev.deps
@@ -72,6 +78,7 @@ poetry run invoke dev.status
```
This should yield a Docker output like the following:
+docs
```shell
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
diff --git a/docs/docs/guides/installation.mdx b/docs/docs/guides/installation.mdx
index 5b22ce085a..0e2b33d674 100644
--- a/docs/docs/guides/installation.mdx
+++ b/docs/docs/guides/installation.mdx
@@ -64,7 +64,7 @@ cd ~/source/infrahub/
Next, clone the Infrahub GitHub repository into the current directory.
```shell
-git clone --recursive --depth 1 https://github.com/opsmill/infrahub.git
+git clone --recursive -b stable --depth 1 https://github.com/opsmill/infrahub.git
```
:::note
diff --git a/docs/docs/guides/jinja2-transform.mdx b/docs/docs/guides/jinja2-transform.mdx
index a3a3938f18..3d38a0920f 100644
--- a/docs/docs/guides/jinja2-transform.mdx
+++ b/docs/docs/guides/jinja2-transform.mdx
@@ -162,6 +162,10 @@ jinja2_transforms:
description: "short description" # (optional)
query: "tags_query" # Name or ID of the GraphQLQuery
template_path: "tags_tpl.j2" # Path to the main Jinja2 template
+
+queries:
+ - name: tags_query # Name of the GraphQLQuery
+ file_path: "tags_query.gql" # Path to the main Jinja2 template
```
> The main Jinja2 template can import other templates
diff --git a/docs/docs/guides/repository.mdx b/docs/docs/guides/repository.mdx
index dba099193e..f963da5a90 100644
--- a/docs/docs/guides/repository.mdx
+++ b/docs/docs/guides/repository.mdx
@@ -83,14 +83,14 @@ Using the GraphQL Interface, it is possible to add a `Repository` or `Read-only
mutation {
CorePasswordCredentialCreate(
data: {
- name: {value: "My Git Credential"},
+ name: {value: "my-git-credential"},
username: {value: "MY_USERNAME"},
password: {value: "MY_TOKEN_OR_PASSWORD"}
}
) {
ok
object {
- id
+ hfid
}
}
}
@@ -108,7 +108,8 @@ Using the GraphQL Interface, it is possible to add a `Repository` or `Read-only
data: {
name: {value: "My Git Repository"},
location: {value: "https://GIT_SERVER/YOUR_GIT_USERNAME/YOUR_REPOSITORY_NAME.git"},
- # credential: {id: "CREDENTIAL_ID_FROM_PREVIOUS_REQUEST"} <-- optional: This needs to be the credential id created at step 2
+ # The HFID returned during step 2 will be the name of the credentials
+ credential: {hfid: "my-git-credential"}
}
) {
ok
@@ -131,7 +132,8 @@ Using the GraphQL Interface, it is possible to add a `Repository` or `Read-only
name: {value: "My Git Repository"},
location: {value: "https://GIT_SERVER/YOUR_GIT_USERNAME/YOUR_REPOSITORY_NAME.git"},
ref: { value: "BRANCH/TAG/COMMIT_TO_TRACK" },
- # credential: {id: "CREDENTIAL_ID_FROM_PREVIOUS_REQUEST"} <-- optional: This needs to be the credential id created at step 2
+ # Optional: the HFID returned during step 2 will be the name of the credentials
+ credential: {hfid: "my-git-credential"}
}
) {
ok
@@ -154,7 +156,7 @@ The repository should be visible under [Unified Storage / Repository](http://loc
### Via the Infrahub SDK
1. Install and setup the [Infrahub SDK](/python-sdk)
-2. If needed, i.e., your repository is private, create a Credential object to hold your username / password.
+2. If needed, i.e., your repository is private, create a Credential object to hold your username / password. We highly recommend to provide credentials for Repository to allow branch creation from Infrahub.
```python
# Create credential object ...
@@ -180,7 +182,8 @@ The repository should be visible under [Unified Storage / Repository](http://loc
"CoreRepository",
name="My Git repository",
location="https://GIT_SERVER/YOUR_GIT_USERNAME/YOUR_REPOSITORY_NAME.git",
- # credential=credential, <-- optional: This needs to be the credential object created at step 2
+ # The credential object created at step 2
+ credential=credential,
)
# and save it ...
@@ -193,11 +196,12 @@ The repository should be visible under [Unified Storage / Repository](http://loc
```python
# Create repository object ...
repository = client.create(
- "CoreRepository",
+ "CoreReadOnlyRepository",
name="My Git repository",
location="https://GIT_SERVER/YOUR_GIT_USERNAME/YOUR_REPOSITORY_NAME.git",
ref="BRANCH/TAG/COMMIT_TO_TRACK",
- # credential=credential, <-- optional: This needs to be the credential object created at step 2
+ # Optional: the credential object created at step 2
+ credential=credential,
)
# and save it ...
diff --git a/docs/docs/guides/sso.mdx b/docs/docs/guides/sso.mdx
new file mode 100644
index 0000000000..e48cfde6a0
--- /dev/null
+++ b/docs/docs/guides/sso.mdx
@@ -0,0 +1,139 @@
+---
+title: Configuring Single sign-on
+---
+# Configuring Single sign-on
+
+In Infrahub you can configure SSO using either Open ID Connect (OIDC) or can use OAuth2.
+
+The SSO system in Infrahub allows for the configuration of one or more identity providers. While most organizations will only use one provider a reason to have two could be that the providers manage different security domains where one of them might be for regular users the other identity provider could be for administrative accounts.
+Infrahub supports three different OIDC providers:
+
+* PROVIDER1
+* PROVIDER2
+* GOOGLE
+
+All of them work in the same way the main difference is that the one for Google includes some predefined settings that limit the amount of configuration you have to do yourself.
+
+When configuring Infrahub, setting up OAuth2 or OIDC is fairly similar, though there are some slight differences with regards to the settings you need to have in place. Both options are provided below.
+
+## Setting up OAuth2 in Infrahub
+
+In this case we are going to focus on PROVIDER1 which allows you to connect Infrahub to your first OAuth2 provider. Configuring the first provider uses environment variables with the `INFRAHUB_OAUTH2_PROVIDER1_` prefix, the others follow suite so it would be `INFRAHUB_OAUTH2_PROVIDER2_` and `INFRAHUB_OAUTH2_GOOGLE_`.
+
+| Variable | Type | Description | Mandatory |
+| ---- | ---- | ----------- | --------- |
+| INFRAHUB_OAUTH2_PROVIDER1_CLIENT_ID | `Text` | The client ID from the IDP | `true` |
+| INFRAHUB_OAUTH2_PROVIDER1_CLIENT_SECRET | `Text` | The client secret from the IDP | `true` |
+| INFRAHUB_OAUTH2_PROVIDER1_AUTHORIZATION_URL | `Url` | The authorization URL on the IDP | `true` |
+| INFRAHUB_OAUTH2_PROVIDER1_TOKEN_URL | `Url` | The token URL on the IDP | `true` |
+| INFRAHUB_OAUTH2_PROVIDER1_USERINFO_URL | `Url` | The userinfo URL on the IDP | `true` |
+| INFRAHUB_OAUTH2_PROVIDER1_SCOPES | `Array[Text]` | The scopes to request from the IDP | `false` |
+| INFRAHUB_OAUTH2_PROVIDER1_DISPLAY_LABEL | `Text` | Display label for the provider on the login screen | `false` |
+| INFRAHUB_OAUTH2_PROVIDER1_ICON | `Text` | MDI icon to display on the login screen (ex: mdi:key) | `false` |
+
+:::note
+
+A difference between this provider and one for Google is that the Google provider only requires `client_id` and `client_secret` to be set, other than that they are currently identical.
+
+:::
+
+Aside from the display label and icon all the other entries will be provided by your OAuth2 provider.
+
+An example of what the configuration could look like:
+
+```bash
+export INFRAHUB_OAUTH2_PROVIDER1_CLIENT_ID=infrahub-sso
+export INFRAHUB_OAUTH2_PROVIDER1_CLIENT_SECRET=edPf4IaquQaqns7t3s95mLhKKYdwL1up
+export INFRAHUB_OAUTH2_PROVIDER1_AUTHORIZATION_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/auth
+export INFRAHUB_OAUTH2_PROVIDER1_TOKEN_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/token
+export INFRAHUB_OAUTH2_PROVIDER1_USERINFO_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/userinfo
+export INFRAHUB_OAUTH2_PROVIDER1_DISPLAY_LABEL="Internal Server (Keycloak)"
+export INFRAHUB_OAUTH2_PROVIDER1_ICON="mdi:security-lock-outline"
+```
+
+This could be the configuration of a Keycloak provider, please refer to the documentation of your intended provider for guides on how to create a client and access the required information.
+
+## Activating the OAuth2 provider
+
+In order to activate the above provider we need to add it to the list of active OAuth2 providers.
+
+```bash
+export INFRAHUB_SECURITY_OAUTH2_PROVIDERS='["provider1"]'
+```
+
+Alternatively if you are setting up multiple providers each with their different settings:
+
+```bash
+export INFRAHUB_SECURITY_OAUTH2_PROVIDERS='["provider1","provider2"]'
+```
+
+## Setting up OIDC in Infrahub
+
+In this case we are going to focus on PROVIDER1 which allows you to connect Infrahub to your first OIDC provider. Configuring the first provider uses environment variables with the `INFRAHUB_OIDC_PROVIDER1_` prefix, the others follow suite so it would be `INFRAHUB_OIDC_PROVIDER2_` and `INFRAHUB_OIDC_GOOGLE_`.
+
+| Variable | Type | Description | Mandatory |
+| ---- | ---- | ----------- | --------- |
+| INFRAHUB_OIDC_PROVIDER1_CLIENT_ID | `Text` | The client ID from the IDP | `true` |
+| INFRAHUB_OIDC_PROVIDER1_CLIENT_SECRET | `Text` | The client secret from the IDP | `true` |
+| INFRAHUB_OIDC_PROVIDER1_DISCOVERY_URL | `Url` | The discovery URL on the IDP | `true` |
+| INFRAHUB_OAUTH2_PROVIDER1_SCOPES | `Array[Text]` | The scopes to request from the IDP | `false` |
+| INFRAHUB_OAUTH2_PROVIDER1_DISPLAY_LABEL | `Text` | Display label for the provider on the login screen | `false` |
+| INFRAHUB_OAUTH2_PROVIDER1_ICON | `Text` | MDI icon to display on the login screen (ex: mdi:key) | `false` |
+
+:::note
+
+A difference between this provider and one for Google is that the Google provider only requires `client_id` and `client_secret` to be set, other than that they are currently identical.
+
+:::
+
+Aside from the display label and icon all the other entries will be provided by from your OIDC provider.
+
+An example of what the configuration could look like:
+
+```bash
+export INFRAHUB_OIDC_PROVIDER1_CLIENT_ID=infrahub-sso
+export INFRAHUB_OIDC_PROVIDER1_CLIENT_SECRET=edPf4IaquQaqns7t3s95mLhKKYdwL1up
+export INFRAHUB_OIDC_PROVIDER1_DISCOVERY_URL=http://localhost:8180/realms/infrahub/.well-known/openid-configuration
+export INFRAHUB_OIDC_PROVIDER1_DISPLAY_LABEL="Internal Server (Keycloak)"
+export INFRAHUB_OIDC_PROVIDER1_ICON="mdi:security-lock-outline"
+```
+
+This could be the configuration of a Keycloak provider, please refer to the documentation of your intended provider for guides on how to create a client and access the required information.
+
+## Activating the OIDC provider
+
+In order to activate the above provider we need to add it to the list of active OIDC providers.
+
+```bash
+export INFRAHUB_SECURITY_OIDC_PROVIDERS='["provider1"]'
+```
+
+Alternatively if you are setting up multiple providers each with their different settings:
+
+```bash
+export INFRAHUB_SECURITY_OIDC_PROVIDERS='["provider1","provider2"]'
+```
+
+## On configuring the redirect URI
+
+Within your identity provider when configuring the client you will need to configure a redirect URI that defines an allowed URI. The convention used for Infrahub is that it should point back to the Infrahub host on `/auth/{protocol}/{provider_name}/callback`.
+
+If we were to setup the above provider on a server called infrahub.example.com to use OIDC the redirect URI would be:
+
+* `https://infrahub.example.com/auth/oidc/provider1/callback`
+
+If we instead use OAuth2 the redirect URI would be:
+
+* `https://infrahub.example.com/auth/oauth2/provider1/callback`
+
+:::note
+
+If you get the redirect URI incorrect this will typically be displayed as an error message on the IDP after Infrahub has redirected the session there.
+
+:::
+
+## Mapping users to groups within Infrahub
+
+After signing in Infrahub will try to collect the groups that the user is member of. The current requirement around this is that the identity provider has to return this information as a list of strings within a "groups" field in the payload returned from the `USERINFO_URL`. This is not something that is supported using the Google provider today but should be configurable in other identity providers such as Keycloak.
+
+For any group that is returned by the IDP provider Infrahub will add the user to that group provided that the group in question exists within Infrahub. I.e. Infrahub will *not* create the groups.
diff --git a/docs/docs/infrahubctl/infrahubctl-protocols.mdx b/docs/docs/infrahubctl/infrahubctl-protocols.mdx
index ea2b8d0778..dd621f2141 100644
--- a/docs/docs/infrahubctl/infrahubctl-protocols.mdx
+++ b/docs/docs/infrahubctl/infrahubctl-protocols.mdx
@@ -10,7 +10,9 @@ $ infrahubctl protocols [OPTIONS]
**Options**:
+* `--schemas PATH`: List of schemas or directory to load.
* `--branch TEXT`: Branch of schema to export Python protocols for.
+* `--sync / --no-sync`: Generate for sync or async. [default: no-sync]
* `--config-file TEXT`: [env var: INFRAHUBCTL_CONFIG; default: infrahubctl.toml]
* `--out TEXT`: Path to a file to save the result. [default: schema_protocols.py]
* `--install-completion`: Install completion for the current shell.
diff --git a/docs/docs/reference/configuration.mdx b/docs/docs/reference/configuration.mdx
index d5b5e660e3..f3556c1ad9 100644
--- a/docs/docs/reference/configuration.mdx
+++ b/docs/docs/reference/configuration.mdx
@@ -30,7 +30,7 @@ Here are a few common methods of setting environmental variables:
| AWS_ACCESS_KEY_ID | | | | |
| AWS_SECRET_ACCESS_KEY | | | | |
| DB_TYPE | | | | |
-| INFRAHUB_ADDRESS | "HTTP endpoint of the API Server, used by the git agent for internal communication" | http://infrahub-server:8000 | | |
+| INFRAHUB_ADDRESS | "HTTP endpoint of the API Server, used by the git agent for internal communication" | http://server:8000 | | |
| INFRAHUB_ALLOW_ANONYMOUS_ACCESS | Indicates if the system allows anonymous read access | TRUE | | |
| INFRAHUB_ANALYTICS_ADDRESS | | | | |
| INFRAHUB_ANALYTICS_API_KEY | | | | |
diff --git a/docs/docs/topics/repository.mdx b/docs/docs/topics/repository.mdx
index 58a2dbae2d..f8c3322234 100644
--- a/docs/docs/topics/repository.mdx
+++ b/docs/docs/topics/repository.mdx
@@ -117,3 +117,16 @@ Sync status keeps track of the synchronisation operation's output.
Sync operation is ongoing.
+
+## Repository actions
+
+From the repository detailed view you can open a "More" menu containing advanced actions to interact with the repository.
+
+
+
+ Infrahub will try to reach the repository and authenticate.
+
+
+ Infrahub will fetch files on the remote repository with the existing commit identifier. This action won't change the reference on Infrahub side (for example pull the latest commit). This might be useful to force an import after having fixed data on Infrahub side.
+
+
diff --git a/docs/package-lock.json b/docs/package-lock.json
index d7f990e744..4195e12381 100644
--- a/docs/package-lock.json
+++ b/docs/package-lock.json
@@ -8,25 +8,25 @@
"name": "infrahub-docs",
"version": "0.0.0",
"dependencies": {
- "@docusaurus/core": "^3.2.1",
- "@docusaurus/preset-classic": "^3.2.1",
- "@easyops-cn/docusaurus-search-local": "^0.40.1",
- "@mdx-js/react": "^3.0.0",
- "clsx": "^2.0.0",
- "prism-react-renderer": "^2.3.0",
+ "@docusaurus/core": "^3.5.2",
+ "@docusaurus/preset-classic": "^3.5.2",
+ "@easyops-cn/docusaurus-search-local": "^0.44.5",
+ "@mdx-js/react": "^3.0.1",
+ "clsx": "^2.1.1",
+ "prism-react-renderer": "^2.4.0",
"raw-loader": "^4.0.2",
- "react": "^18.0.0",
- "react-dom": "^18.0.0"
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
},
"devDependencies": {
- "@docusaurus/eslint-plugin": "^3.2.1",
- "@docusaurus/module-type-aliases": "^3.2.1",
- "@docusaurus/tsconfig": "^3.2.1",
- "@docusaurus/types": "^3.2.1",
+ "@docusaurus/eslint-plugin": "^3.5.2",
+ "@docusaurus/module-type-aliases": "^3.5.2",
+ "@docusaurus/tsconfig": "^3.5.2",
+ "@docusaurus/types": "^3.5.2",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"eslint": "^8.56.0",
- "typescript": "~5.2.2"
+ "typescript": "~5.6.2"
},
"engines": {
"node": ">=18.0"
@@ -45,6 +45,7 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz",
"integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==",
+ "license": "MIT",
"dependencies": {
"@algolia/autocomplete-plugin-algolia-insights": "1.9.3",
"@algolia/autocomplete-shared": "1.9.3"
@@ -54,6 +55,7 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz",
"integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==",
+ "license": "MIT",
"dependencies": {
"@algolia/autocomplete-shared": "1.9.3"
},
@@ -65,6 +67,7 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz",
"integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==",
+ "license": "MIT",
"dependencies": {
"@algolia/autocomplete-shared": "1.9.3"
},
@@ -77,147 +80,281 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz",
"integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==",
+ "license": "MIT",
"peerDependencies": {
"@algolia/client-search": ">= 4.9.1 < 6",
"algoliasearch": ">= 4.9.1 < 6"
}
},
"node_modules/@algolia/cache-browser-local-storage": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.23.3.tgz",
- "integrity": "sha512-vRHXYCpPlTDE7i6UOy2xE03zHF2C8MEFjPN2v7fRbqVpcOvAUQK81x3Kc21xyb5aSIpYCjWCZbYZuz8Glyzyyg==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz",
+ "integrity": "sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==",
+ "license": "MIT",
"dependencies": {
- "@algolia/cache-common": "4.23.3"
+ "@algolia/cache-common": "4.24.0"
}
},
"node_modules/@algolia/cache-common": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.23.3.tgz",
- "integrity": "sha512-h9XcNI6lxYStaw32pHpB1TMm0RuxphF+Ik4o7tcQiodEdpKK+wKufY6QXtba7t3k8eseirEMVB83uFFF3Nu54A=="
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.24.0.tgz",
+ "integrity": "sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==",
+ "license": "MIT"
},
"node_modules/@algolia/cache-in-memory": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.23.3.tgz",
- "integrity": "sha512-yvpbuUXg/+0rbcagxNT7un0eo3czx2Uf0y4eiR4z4SD7SiptwYTpbuS0IHxcLHG3lq22ukx1T6Kjtk/rT+mqNg==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz",
+ "integrity": "sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==",
+ "license": "MIT",
"dependencies": {
- "@algolia/cache-common": "4.23.3"
+ "@algolia/cache-common": "4.24.0"
}
},
"node_modules/@algolia/client-account": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.23.3.tgz",
- "integrity": "sha512-hpa6S5d7iQmretHHF40QGq6hz0anWEHGlULcTIT9tbUssWUriN9AUXIFQ8Ei4w9azD0hc1rUok9/DeQQobhQMA==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.24.0.tgz",
+ "integrity": "sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==",
+ "license": "MIT",
"dependencies": {
- "@algolia/client-common": "4.23.3",
- "@algolia/client-search": "4.23.3",
- "@algolia/transporter": "4.23.3"
+ "@algolia/client-common": "4.24.0",
+ "@algolia/client-search": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/client-account/node_modules/@algolia/client-common": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz",
+ "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/client-account/node_modules/@algolia/client-search": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz",
+ "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/client-common": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
}
},
"node_modules/@algolia/client-analytics": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.23.3.tgz",
- "integrity": "sha512-LBsEARGS9cj8VkTAVEZphjxTjMVCci+zIIiRhpFun9jGDUlS1XmhCW7CTrnaWeIuCQS/2iPyRqSy1nXPjcBLRA==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.24.0.tgz",
+ "integrity": "sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==",
+ "license": "MIT",
"dependencies": {
- "@algolia/client-common": "4.23.3",
- "@algolia/client-search": "4.23.3",
- "@algolia/requester-common": "4.23.3",
- "@algolia/transporter": "4.23.3"
+ "@algolia/client-common": "4.24.0",
+ "@algolia/client-search": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
}
},
- "node_modules/@algolia/client-common": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.23.3.tgz",
- "integrity": "sha512-l6EiPxdAlg8CYhroqS5ybfIczsGUIAC47slLPOMDeKSVXYG1n0qGiz4RjAHLw2aD0xzh2EXZ7aRguPfz7UKDKw==",
+ "node_modules/@algolia/client-analytics/node_modules/@algolia/client-common": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz",
+ "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/client-analytics/node_modules/@algolia/client-search": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz",
+ "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==",
+ "license": "MIT",
"dependencies": {
- "@algolia/requester-common": "4.23.3",
- "@algolia/transporter": "4.23.3"
+ "@algolia/client-common": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/client-common": {
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.6.1.tgz",
+ "integrity": "sha512-4MGqXqiAyqsUJw+KamKWZO2Gxn9iMpc05vC0vy8+iQRjKRZEDB1a+3Da6CnkWzXa162pJb7a/chDAAKA9rye8A==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">= 14.0.0"
}
},
"node_modules/@algolia/client-personalization": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.23.3.tgz",
- "integrity": "sha512-3E3yF3Ocr1tB/xOZiuC3doHQBQ2zu2MPTYZ0d4lpfWads2WTKG7ZzmGnsHmm63RflvDeLK/UVx7j2b3QuwKQ2g==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.24.0.tgz",
+ "integrity": "sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==",
+ "license": "MIT",
"dependencies": {
- "@algolia/client-common": "4.23.3",
- "@algolia/requester-common": "4.23.3",
- "@algolia/transporter": "4.23.3"
+ "@algolia/client-common": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/client-personalization/node_modules/@algolia/client-common": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz",
+ "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
}
},
"node_modules/@algolia/client-search": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.23.3.tgz",
- "integrity": "sha512-P4VAKFHqU0wx9O+q29Q8YVuaowaZ5EM77rxfmGnkHUJggh28useXQdopokgwMeYw2XUht49WX5RcTQ40rZIabw==",
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.6.1.tgz",
+ "integrity": "sha512-HloeR0Ef29vf2yJc1lhjw1OYial3YgB0f3TQaqqMlSnM/IkAw9TnX1IOYLurnI91apMKggFpA9t8lRp7TGEKEg==",
+ "license": "MIT",
+ "peer": true,
"dependencies": {
- "@algolia/client-common": "4.23.3",
- "@algolia/requester-common": "4.23.3",
- "@algolia/transporter": "4.23.3"
+ "@algolia/client-common": "5.6.1",
+ "@algolia/requester-browser-xhr": "5.6.1",
+ "@algolia/requester-fetch": "5.6.1",
+ "@algolia/requester-node-http": "5.6.1"
+ },
+ "engines": {
+ "node": ">= 14.0.0"
}
},
"node_modules/@algolia/events": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz",
- "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ=="
+ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==",
+ "license": "MIT"
},
"node_modules/@algolia/logger-common": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.23.3.tgz",
- "integrity": "sha512-y9kBtmJwiZ9ZZ+1Ek66P0M68mHQzKRxkW5kAAXYN/rdzgDN0d2COsViEFufxJ0pb45K4FRcfC7+33YB4BLrZ+g=="
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.24.0.tgz",
+ "integrity": "sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==",
+ "license": "MIT"
},
"node_modules/@algolia/logger-console": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.23.3.tgz",
- "integrity": "sha512-8xoiseoWDKuCVnWP8jHthgaeobDLolh00KJAdMe9XPrWPuf1by732jSpgy2BlsLTaT9m32pHI8CRfrOqQzHv3A==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.24.0.tgz",
+ "integrity": "sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==",
+ "license": "MIT",
"dependencies": {
- "@algolia/logger-common": "4.23.3"
+ "@algolia/logger-common": "4.24.0"
}
},
"node_modules/@algolia/recommend": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.23.3.tgz",
- "integrity": "sha512-9fK4nXZF0bFkdcLBRDexsnGzVmu4TSYZqxdpgBW2tEyfuSSY54D4qSRkLmNkrrz4YFvdh2GM1gA8vSsnZPR73w==",
- "dependencies": {
- "@algolia/cache-browser-local-storage": "4.23.3",
- "@algolia/cache-common": "4.23.3",
- "@algolia/cache-in-memory": "4.23.3",
- "@algolia/client-common": "4.23.3",
- "@algolia/client-search": "4.23.3",
- "@algolia/logger-common": "4.23.3",
- "@algolia/logger-console": "4.23.3",
- "@algolia/requester-browser-xhr": "4.23.3",
- "@algolia/requester-common": "4.23.3",
- "@algolia/requester-node-http": "4.23.3",
- "@algolia/transporter": "4.23.3"
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.24.0.tgz",
+ "integrity": "sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/cache-browser-local-storage": "4.24.0",
+ "@algolia/cache-common": "4.24.0",
+ "@algolia/cache-in-memory": "4.24.0",
+ "@algolia/client-common": "4.24.0",
+ "@algolia/client-search": "4.24.0",
+ "@algolia/logger-common": "4.24.0",
+ "@algolia/logger-console": "4.24.0",
+ "@algolia/requester-browser-xhr": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/requester-node-http": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/recommend/node_modules/@algolia/client-common": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz",
+ "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/recommend/node_modules/@algolia/client-search": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz",
+ "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/client-common": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/recommend/node_modules/@algolia/requester-browser-xhr": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz",
+ "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0"
+ }
+ },
+ "node_modules/@algolia/recommend/node_modules/@algolia/requester-node-http": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz",
+ "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0"
}
},
"node_modules/@algolia/requester-browser-xhr": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.23.3.tgz",
- "integrity": "sha512-jDWGIQ96BhXbmONAQsasIpTYWslyjkiGu0Quydjlowe+ciqySpiDUrJHERIRfELE5+wFc7hc1Q5hqjGoV7yghw==",
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.6.1.tgz",
+ "integrity": "sha512-tY1RW60sGF9sMpxbd8j53IqLLwnkNhrAarVhFfNZzDZNvI8WyzG78W5ZD/SFvtkgNPPSav3T/3LpBT8xBpzbGw==",
+ "license": "MIT",
+ "peer": true,
"dependencies": {
- "@algolia/requester-common": "4.23.3"
+ "@algolia/client-common": "5.6.1"
+ },
+ "engines": {
+ "node": ">= 14.0.0"
}
},
"node_modules/@algolia/requester-common": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.23.3.tgz",
- "integrity": "sha512-xloIdr/bedtYEGcXCiF2muajyvRhwop4cMZo+K2qzNht0CMzlRkm8YsDdj5IaBhshqfgmBb3rTg4sL4/PpvLYw=="
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.24.0.tgz",
+ "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==",
+ "license": "MIT"
+ },
+ "node_modules/@algolia/requester-fetch": {
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.6.1.tgz",
+ "integrity": "sha512-4TvR5IodrH+o+ji4ka+VBufWY0GfHr43nFqnDTStabtjspfo4rlcV16x534vvnbfp694oBxrz0SO/Ny8VemvXg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@algolia/client-common": "5.6.1"
+ },
+ "engines": {
+ "node": ">= 14.0.0"
+ }
},
"node_modules/@algolia/requester-node-http": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.23.3.tgz",
- "integrity": "sha512-zgu++8Uj03IWDEJM3fuNl34s746JnZOWn1Uz5taV1dFyJhVM/kTNw9Ik7YJWiUNHJQXcaD8IXD1eCb0nq/aByA==",
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.6.1.tgz",
+ "integrity": "sha512-K7tlss87aq6UnWnU8+fPIe+Is9Mvyqwzysp6Ty/HpQ7YNKUU7opgkMOVKxzTwt3fm40NfNX4ENvVKHoYABL6vw==",
+ "license": "MIT",
+ "peer": true,
"dependencies": {
- "@algolia/requester-common": "4.23.3"
+ "@algolia/client-common": "5.6.1"
+ },
+ "engines": {
+ "node": ">= 14.0.0"
}
},
"node_modules/@algolia/transporter": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.23.3.tgz",
- "integrity": "sha512-Wjl5gttqnf/gQKJA+dafnD0Y6Yw97yvfY8R9h0dQltX1GXTgNs1zWgvtWW0tHl1EgMdhAyw189uWiZMnL3QebQ==",
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.24.0.tgz",
+ "integrity": "sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==",
+ "license": "MIT",
"dependencies": {
- "@algolia/cache-common": "4.23.3",
- "@algolia/logger-common": "4.23.3",
- "@algolia/requester-common": "4.23.3"
+ "@algolia/cache-common": "4.24.0",
+ "@algolia/logger-common": "4.24.0",
+ "@algolia/requester-common": "4.24.0"
}
},
"node_modules/@ampproject/remapping": {
@@ -564,9 +701,10 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
- "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz",
+ "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==",
+ "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@@ -1641,11 +1779,12 @@
}
},
"node_modules/@babel/plugin-transform-react-constant-elements": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.23.3.tgz",
- "integrity": "sha512-zP0QKq/p6O42OL94udMgSfKXyse4RyJ0JqbQ34zDAONWjyrEsghYEyTSK5FIpmXmCpB55SHokL1cRRKHv8L2Qw==",
+ "version": "7.25.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.1.tgz",
+ "integrity": "sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ==",
+ "license": "MIT",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.22.5"
+ "@babel/helper-plugin-utils": "^7.24.8"
},
"engines": {
"node": ">=6.9.0"
@@ -2161,18 +2300,20 @@
}
},
"node_modules/@docsearch/css": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.0.tgz",
- "integrity": "sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ=="
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.2.tgz",
+ "integrity": "sha512-vKNZepO2j7MrYBTZIGXvlUOIR+v9KRf70FApRgovWrj3GTs1EITz/Xb0AOlm1xsQBp16clVZj1SY/qaOJbQtZw==",
+ "license": "MIT"
},
"node_modules/@docsearch/react": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.0.tgz",
- "integrity": "sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.2.tgz",
+ "integrity": "sha512-rtZce46OOkVflCQH71IdbXSFK+S8iJZlUF56XBW5rIgx/eG5qoomC7Ag3anZson1bBac/JFQn7XOBfved/IMRA==",
+ "license": "MIT",
"dependencies": {
"@algolia/autocomplete-core": "1.9.3",
"@algolia/autocomplete-preset-algolia": "1.9.3",
- "@docsearch/css": "3.6.0",
+ "@docsearch/css": "3.6.2",
"algoliasearch": "^4.19.1"
},
"peerDependencies": {
@@ -2197,9 +2338,10 @@
}
},
"node_modules/@docusaurus/core": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.2.1.tgz",
- "integrity": "sha512-ZeMAqNvy0eBv2dThEeMuNzzuu+4thqMQakhxsgT5s02A8LqRcdkg+rbcnuNqUIpekQ4GRx3+M5nj0ODJhBXo9w==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.5.2.tgz",
+ "integrity": "sha512-4Z1WkhCSkX4KO0Fw5m/Vuc7Q3NxBG53NE5u59Rs96fWkMPZVSrzEPP16/Nk6cWb/shK7xXPndTmalJtw7twL/w==",
+ "license": "MIT",
"dependencies": {
"@babel/core": "^7.23.3",
"@babel/generator": "^7.23.3",
@@ -2211,14 +2353,12 @@
"@babel/runtime": "^7.22.6",
"@babel/runtime-corejs3": "^7.22.6",
"@babel/traverse": "^7.22.8",
- "@docusaurus/cssnano-preset": "3.2.1",
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/mdx-loader": "3.2.1",
- "@docusaurus/react-loadable": "5.5.2",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
- "@svgr/webpack": "^6.5.1",
+ "@docusaurus/cssnano-preset": "3.5.2",
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/mdx-loader": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"autoprefixer": "^10.4.14",
"babel-loader": "^9.1.3",
"babel-plugin-dynamic-import-node": "^2.3.3",
@@ -2232,8 +2372,8 @@
"copy-webpack-plugin": "^11.0.0",
"core-js": "^3.31.1",
"css-loader": "^6.8.1",
- "css-minimizer-webpack-plugin": "^4.2.2",
- "cssnano": "^5.1.15",
+ "css-minimizer-webpack-plugin": "^5.0.1",
+ "cssnano": "^6.1.2",
"del": "^6.1.1",
"detect-port": "^1.5.1",
"escape-html": "^1.0.3",
@@ -2253,7 +2393,7 @@
"prompts": "^2.4.2",
"react-dev-utils": "^12.0.1",
"react-helmet-async": "^1.3.0",
- "react-loadable": "npm:@docusaurus/react-loadable@5.5.2",
+ "react-loadable": "npm:@docusaurus/react-loadable@6.0.0",
"react-loadable-ssr-addon-v5-slorber": "^1.0.1",
"react-router": "^5.3.4",
"react-router-config": "^5.1.1",
@@ -2279,18 +2419,20 @@
"node": ">=18.0"
},
"peerDependencies": {
+ "@mdx-js/react": "^3.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/cssnano-preset": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.2.1.tgz",
- "integrity": "sha512-wTL9KuSSbMJjKrfu385HZEzAoamUsbKqwscAQByZw4k6Ja/RWpqgVvt/CbAC+aYEH6inLzOt+MjuRwMOrD3VBA==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.5.2.tgz",
+ "integrity": "sha512-D3KiQXOMA8+O0tqORBrTOEQyQxNIfPm9jEaJoALjjSjc2M/ZAWcUfPQEnwr2JB2TadHw2gqWgpZckQmrVWkytA==",
+ "license": "MIT",
"dependencies": {
- "cssnano-preset-advanced": "^5.3.10",
- "postcss": "^8.4.26",
- "postcss-sort-media-queries": "^4.4.1",
+ "cssnano-preset-advanced": "^6.1.2",
+ "postcss": "^8.4.38",
+ "postcss-sort-media-queries": "^5.2.0",
"tslib": "^2.6.0"
},
"engines": {
@@ -2298,10 +2440,11 @@
}
},
"node_modules/@docusaurus/eslint-plugin": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/eslint-plugin/-/eslint-plugin-3.2.1.tgz",
- "integrity": "sha512-DIhptlFPvSFZm7ZyisxorEzWK6SF0SvyHTR5NzljnGSTn8lln9mlc18xYhm0zYI/TLoDRGN/fkwCMWPkxB8YVQ==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/eslint-plugin/-/eslint-plugin-3.5.2.tgz",
+ "integrity": "sha512-9zBtXQwRgj2unY+peS5HIISvG7kDQDoWl8dZ+sN41B2qIctNUWpBFkFAPHZSPy2cvEDQwWshNpPYDjp+sv+CVA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@typescript-eslint/utils": "^5.62.0",
"tslib": "^2.6.0"
@@ -2414,9 +2557,10 @@
}
},
"node_modules/@docusaurus/logger": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.2.1.tgz",
- "integrity": "sha512-0voOKJCn9RaM3np6soqEfo7SsVvf2C+CDTWhW+H/1AyBhybASpExtDEz+7ECck9TwPzFQ5tt+I3zVugUJbJWDg==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.5.2.tgz",
+ "integrity": "sha512-LHC540SGkeLfyT3RHK3gAMK6aS5TRqOD4R72BEU/DE2M/TY8WwEUAMY576UUc/oNJXv8pGhBmQB6N9p3pt8LQw==",
+ "license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"tslib": "^2.6.0"
@@ -2426,13 +2570,14 @@
}
},
"node_modules/@docusaurus/mdx-loader": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz",
- "integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.5.2.tgz",
+ "integrity": "sha512-ku3xO9vZdwpiMIVd8BzWV0DCqGEbCP5zs1iHfKX50vw6jX8vQo0ylYo1YJMZyz6e+JFJ17HYHT5FzVidz2IflA==",
+ "license": "MIT",
"dependencies": {
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
@@ -2464,18 +2609,18 @@
}
},
"node_modules/@docusaurus/module-type-aliases": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.2.1.tgz",
- "integrity": "sha512-FyViV5TqhL1vsM7eh29nJ5NtbRE6Ra6LP1PDcPvhwPSlA7eiWGRKAn3jWwMUcmjkos5SYY+sr0/feCdbM3eQHQ==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.5.2.tgz",
+ "integrity": "sha512-Z+Xu3+2rvKef/YKTMxZHsEXp1y92ac0ngjDiExRdqGTmEKtCUpkbNYH8v5eXo5Ls+dnW88n6WTa+Q54kLOkwPg==",
+ "license": "MIT",
"dependencies": {
- "@docusaurus/react-loadable": "5.5.2",
- "@docusaurus/types": "3.2.1",
+ "@docusaurus/types": "3.5.2",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
"@types/react-router-dom": "*",
"react-helmet-async": "*",
- "react-loadable": "npm:@docusaurus/react-loadable@5.5.2"
+ "react-loadable": "npm:@docusaurus/react-loadable@6.0.0"
},
"peerDependencies": {
"react": "*",
@@ -2483,18 +2628,20 @@
}
},
"node_modules/@docusaurus/plugin-content-blog": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.2.1.tgz",
- "integrity": "sha512-lOx0JfhlGZoZu6pEJfeEpSISZR5dQbJGGvb42IP13G5YThNHhG9R9uoWuo4IOimPqBC7sHThdLA3VLevk61Fsw==",
- "dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/mdx-loader": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
- "cheerio": "^1.0.0-rc.12",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.5.2.tgz",
+ "integrity": "sha512-R7ghWnMvjSf+aeNDH0K4fjyQnt5L0KzUEnUhmf1e3jZrv3wogeytZNN6n7X8yHcMsuZHPOrctQhXWnmxu+IRRg==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/mdx-loader": "3.5.2",
+ "@docusaurus/theme-common": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
+ "cheerio": "1.0.0-rc.12",
"feed": "^4.2.2",
"fs-extra": "^11.1.1",
"lodash": "^4.17.21",
@@ -2509,23 +2656,26 @@
"node": ">=18.0"
},
"peerDependencies": {
+ "@docusaurus/plugin-content-docs": "*",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/plugin-content-docs": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.2.1.tgz",
- "integrity": "sha512-GHe5b/lCskAR8QVbfWAfPAApvRZgqk7FN3sOHgjCtjzQACZxkHmq6QqyqZ8Jp45V7lVck4wt2Xw2IzBJ7Cz3bA==",
- "dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/mdx-loader": "3.2.1",
- "@docusaurus/module-type-aliases": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.5.2.tgz",
+ "integrity": "sha512-Bt+OXn/CPtVqM3Di44vHjE7rPCEsRCB/DMo2qoOuozB9f7+lsdrHvD0QCHdBs0uhz6deYJDppAr2VgqybKPlVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/mdx-loader": "3.5.2",
+ "@docusaurus/module-type-aliases": "3.5.2",
+ "@docusaurus/theme-common": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"@types/react-router-config": "^5.0.7",
"combine-promises": "^1.1.0",
"fs-extra": "^11.1.1",
@@ -2544,15 +2694,16 @@
}
},
"node_modules/@docusaurus/plugin-content-pages": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.2.1.tgz",
- "integrity": "sha512-TOqVfMVTAHqWNEGM94Drz+PUpHDbwFy6ucHFgyTx9zJY7wPNSG5EN+rd/mU7OvAi26qpOn2o9xTdUmb28QLjEQ==",
- "dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/mdx-loader": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.5.2.tgz",
+ "integrity": "sha512-WzhHjNpoQAUz/ueO10cnundRz+VUtkjFhhaQ9jApyv1a46FPURO4cef89pyNIOMny1fjDz/NUN2z6Yi+5WUrCw==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/mdx-loader": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"fs-extra": "^11.1.1",
"tslib": "^2.6.0",
"webpack": "^5.88.1"
@@ -2566,13 +2717,14 @@
}
},
"node_modules/@docusaurus/plugin-debug": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.2.1.tgz",
- "integrity": "sha512-AMKq8NuUKf2sRpN1m/sIbqbRbnmk+rSA+8mNU1LNxEl9BW9F/Gng8m9HKlzeyMPrf5XidzS1jqkuTLDJ6KIrFw==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.5.2.tgz",
+ "integrity": "sha512-kBK6GlN0itCkrmHuCS6aX1wmoWc5wpd5KJlqQ1FyrF0cLDnvsYSnh7+ftdwzt7G6lGBho8lrVwkkL9/iQvaSOA==",
+ "license": "MIT",
"dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils": "3.2.1",
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
"fs-extra": "^11.1.1",
"react-json-view-lite": "^1.2.0",
"tslib": "^2.6.0"
@@ -2586,13 +2738,14 @@
}
},
"node_modules/@docusaurus/plugin-google-analytics": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.2.1.tgz",
- "integrity": "sha512-/rJ+9u+Px0eTCiF4TNcNtj3kHf8cp6K1HCwOTdbsSlz6Xn21syZYcy+f1VM9wF6HrvUkXUcbM5TDCvg2IRL6bQ==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.5.2.tgz",
+ "integrity": "sha512-rjEkJH/tJ8OXRE9bwhV2mb/WP93V441rD6XnM6MIluu7rk8qg38iSxS43ga2V2Q/2ib53PcqbDEJDG/yWQRJhQ==",
+ "license": "MIT",
"dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"tslib": "^2.6.0"
},
"engines": {
@@ -2604,13 +2757,14 @@
}
},
"node_modules/@docusaurus/plugin-google-gtag": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.2.1.tgz",
- "integrity": "sha512-XtuJnlMvYfppeVdUyKiDIJAa/gTJKCQU92z8CLZZ9ibJdgVjFOLS10s0hIC0eL5z0U2u2loJz2rZ63HOkNHbBA==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.5.2.tgz",
+ "integrity": "sha512-lm8XL3xLkTPHFKKjLjEEAHUrW0SZBSHBE1I+i/tmYMBsjCcUB5UJ52geS5PSiOCFVR74tbPGcPHEV/gaaxFeSA==",
+ "license": "MIT",
"dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"@types/gtag.js": "^0.0.12",
"tslib": "^2.6.0"
},
@@ -2623,13 +2777,14 @@
}
},
"node_modules/@docusaurus/plugin-google-tag-manager": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.2.1.tgz",
- "integrity": "sha512-wiS/kE0Ny5pnjTxVCs8ljRnkL1RVMj59t6jmSsgEX7piDOoaXSMIUaoIt9ogS/v132uO0xEsxHstkRUZHQyPcQ==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.5.2.tgz",
+ "integrity": "sha512-QkpX68PMOMu10Mvgvr5CfZAzZQFx8WLlOiUQ/Qmmcl6mjGK6H21WLT5x7xDmcpCoKA/3CegsqIqBR+nA137lQg==",
+ "license": "MIT",
"dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"tslib": "^2.6.0"
},
"engines": {
@@ -2641,16 +2796,17 @@
}
},
"node_modules/@docusaurus/plugin-sitemap": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.2.1.tgz",
- "integrity": "sha512-uWZ7AxzdeaQSTCwD2yZtOiEm9zyKU+wqCmi/Sf25kQQqqFSBZUStXfaQ8OHP9cecnw893ZpZ811rPhB/wfujJw==",
- "dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.5.2.tgz",
+ "integrity": "sha512-DnlqYyRAdQ4NHY28TfHuVk414ft2uruP4QWCH//jzpHjqvKyXjj2fmDtI8RPUBh9K8iZKFMHRnLtzJKySPWvFA==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"fs-extra": "^11.1.1",
"sitemap": "^7.1.1",
"tslib": "^2.6.0"
@@ -2664,23 +2820,24 @@
}
},
"node_modules/@docusaurus/preset-classic": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.2.1.tgz",
- "integrity": "sha512-E3OHSmttpEBcSMhfPBq3EJMBxZBM01W1rnaCUTXy9EHvkmB5AwgTfW1PwGAybPAX579ntE03R+2zmXdizWfKnQ==",
- "dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/plugin-content-blog": "3.2.1",
- "@docusaurus/plugin-content-docs": "3.2.1",
- "@docusaurus/plugin-content-pages": "3.2.1",
- "@docusaurus/plugin-debug": "3.2.1",
- "@docusaurus/plugin-google-analytics": "3.2.1",
- "@docusaurus/plugin-google-gtag": "3.2.1",
- "@docusaurus/plugin-google-tag-manager": "3.2.1",
- "@docusaurus/plugin-sitemap": "3.2.1",
- "@docusaurus/theme-classic": "3.2.1",
- "@docusaurus/theme-common": "3.2.1",
- "@docusaurus/theme-search-algolia": "3.2.1",
- "@docusaurus/types": "3.2.1"
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.5.2.tgz",
+ "integrity": "sha512-3ihfXQ95aOHiLB5uCu+9PRy2gZCeSZoDcqpnDvf3B+sTrMvMTr8qRUzBvWkoIqc82yG5prCboRjk1SVILKx6sg==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/plugin-content-blog": "3.5.2",
+ "@docusaurus/plugin-content-docs": "3.5.2",
+ "@docusaurus/plugin-content-pages": "3.5.2",
+ "@docusaurus/plugin-debug": "3.5.2",
+ "@docusaurus/plugin-google-analytics": "3.5.2",
+ "@docusaurus/plugin-google-gtag": "3.5.2",
+ "@docusaurus/plugin-google-tag-manager": "3.5.2",
+ "@docusaurus/plugin-sitemap": "3.5.2",
+ "@docusaurus/theme-classic": "3.5.2",
+ "@docusaurus/theme-common": "3.5.2",
+ "@docusaurus/theme-search-algolia": "3.5.2",
+ "@docusaurus/types": "3.5.2"
},
"engines": {
"node": ">=18.0"
@@ -2690,39 +2847,28 @@
"react-dom": "^18.0.0"
}
},
- "node_modules/@docusaurus/react-loadable": {
- "version": "5.5.2",
- "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz",
- "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==",
- "dependencies": {
- "@types/react": "*",
- "prop-types": "^15.6.2"
- },
- "peerDependencies": {
- "react": "*"
- }
- },
"node_modules/@docusaurus/theme-classic": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.2.1.tgz",
- "integrity": "sha512-+vSbnQyoWjc6vRZi4vJO2dBU02wqzynsai15KK+FANZudrYaBHtkbLZAQhgmxzBGVpxzi87gRohlMm+5D8f4tA==",
- "dependencies": {
- "@docusaurus/core": "3.2.1",
- "@docusaurus/mdx-loader": "3.2.1",
- "@docusaurus/module-type-aliases": "3.2.1",
- "@docusaurus/plugin-content-blog": "3.2.1",
- "@docusaurus/plugin-content-docs": "3.2.1",
- "@docusaurus/plugin-content-pages": "3.2.1",
- "@docusaurus/theme-common": "3.2.1",
- "@docusaurus/theme-translations": "3.2.1",
- "@docusaurus/types": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.5.2.tgz",
+ "integrity": "sha512-XRpinSix3NBv95Rk7xeMF9k4safMkwnpSgThn0UNQNumKvmcIYjfkwfh2BhwYh/BxMXQHJ/PdmNh22TQFpIaYg==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/mdx-loader": "3.5.2",
+ "@docusaurus/module-type-aliases": "3.5.2",
+ "@docusaurus/plugin-content-blog": "3.5.2",
+ "@docusaurus/plugin-content-docs": "3.5.2",
+ "@docusaurus/plugin-content-pages": "3.5.2",
+ "@docusaurus/theme-common": "3.5.2",
+ "@docusaurus/theme-translations": "3.5.2",
+ "@docusaurus/types": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"copy-text-to-clipboard": "^3.2.0",
- "infima": "0.2.0-alpha.43",
+ "infima": "0.2.0-alpha.44",
"lodash": "^4.17.21",
"nprogress": "^0.2.0",
"postcss": "^8.4.26",
@@ -2742,17 +2888,15 @@
}
},
"node_modules/@docusaurus/theme-common": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.2.1.tgz",
- "integrity": "sha512-d+adiD7L9xv6EvfaAwUqdKf4orsM3jqgeqAM+HAjgL/Ux0GkVVnfKr+tsoe+4ow4rHe6NUt+nkkW8/K8dKdilA==",
- "dependencies": {
- "@docusaurus/mdx-loader": "3.2.1",
- "@docusaurus/module-type-aliases": "3.2.1",
- "@docusaurus/plugin-content-blog": "3.2.1",
- "@docusaurus/plugin-content-docs": "3.2.1",
- "@docusaurus/plugin-content-pages": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.5.2.tgz",
+ "integrity": "sha512-QXqlm9S6x9Ibwjs7I2yEDgsCocp708DrCrgHgKwg2n2AY0YQ6IjU0gAK35lHRLOvAoJUfCKpQAwUykB0R7+Eew==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/mdx-loader": "3.5.2",
+ "@docusaurus/module-type-aliases": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@@ -2766,23 +2910,25 @@
"node": ">=18.0"
},
"peerDependencies": {
+ "@docusaurus/plugin-content-docs": "*",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@docusaurus/theme-search-algolia": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.2.1.tgz",
- "integrity": "sha512-bzhCrpyXBXzeydNUH83II2akvFEGfhsNTPPWsk5N7e+odgQCQwoHhcF+2qILbQXjaoZ6B3c48hrvkyCpeyqGHw==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.5.2.tgz",
+ "integrity": "sha512-qW53kp3VzMnEqZGjakaV90sst3iN1o32PH+nawv1uepROO8aEGxptcq2R5rsv7aBShSRbZwIobdvSYKsZ5pqvA==",
+ "license": "MIT",
"dependencies": {
"@docsearch/react": "^3.5.2",
- "@docusaurus/core": "3.2.1",
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/plugin-content-docs": "3.2.1",
- "@docusaurus/theme-common": "3.2.1",
- "@docusaurus/theme-translations": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-validation": "3.2.1",
+ "@docusaurus/core": "3.5.2",
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/plugin-content-docs": "3.5.2",
+ "@docusaurus/theme-common": "3.5.2",
+ "@docusaurus/theme-translations": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-validation": "3.5.2",
"algoliasearch": "^4.18.0",
"algoliasearch-helper": "^3.13.3",
"clsx": "^2.0.0",
@@ -2801,9 +2947,10 @@
}
},
"node_modules/@docusaurus/theme-translations": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.2.1.tgz",
- "integrity": "sha512-jAUMkIkFfY+OAhJhv6mV8zlwY6J4AQxJPTgLdR2l+Otof9+QdJjHNh/ifVEu9q0lp3oSPlJj9l05AaP7Ref+cg==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.5.2.tgz",
+ "integrity": "sha512-GPZLcu4aT1EmqSTmbdpVrDENGR2yObFEX8ssEFYTCiAIVc0EihNSdOIBTazUvgNqwvnoU1A8vIs1xyzc3LITTw==",
+ "license": "MIT",
"dependencies": {
"fs-extra": "^11.1.1",
"tslib": "^2.6.0"
@@ -2813,15 +2960,17 @@
}
},
"node_modules/@docusaurus/tsconfig": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.2.1.tgz",
- "integrity": "sha512-+biUwtsYW3oChLxYezzA+NIgS3Q9KDRl7add/YT54RXs9Q4rKInebxdHdG6JFs5BaTg45gyjDu0rvNVcGeHODg==",
- "dev": true
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.5.2.tgz",
+ "integrity": "sha512-rQ7toURCFnWAIn8ubcquDs0ewhPwviMzxh6WpRjBW7sJVCXb6yzwUaY3HMNa0VXCFw+qkIbFywrMTf+Pb4uHWQ==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@docusaurus/types": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.2.1.tgz",
- "integrity": "sha512-n/toxBzL2oxTtRTOFiGKsHypzn/Pm+sXyw+VSk1UbqbXQiHOwHwts55bpKwbcUgA530Is6kix3ELiFOv9GAMfw==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.5.2.tgz",
+ "integrity": "sha512-N6GntLXoLVUwkZw7zCxwy9QiuEXIcTVzA9AkmNw16oc0AP3SXLrMmDMMBIfgqwuKWa6Ox6epHol9kMtJqekACw==",
+ "license": "MIT",
"dependencies": {
"@mdx-js/mdx": "^3.0.0",
"@types/history": "^4.7.11",
@@ -2839,13 +2988,14 @@
}
},
"node_modules/@docusaurus/utils": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.2.1.tgz",
- "integrity": "sha512-DPkIS/EPc+pGAV798PUXgNzJFM3HJouoQXgr0KDZuJVz1EkWbDLOcQwLIz8Qx7liI9ddfkN/TXTRQdsTPZNakw==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.5.2.tgz",
+ "integrity": "sha512-33QvcNFh+Gv+C2dP9Y9xWEzMgf3JzrpL2nW9PopidiohS1nDcyknKRx2DWaFvyVTTYIkkABVSr073VTj/NITNA==",
+ "license": "MIT",
"dependencies": {
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
- "@svgr/webpack": "^6.5.1",
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
+ "@svgr/webpack": "^8.1.0",
"escape-string-regexp": "^4.0.0",
"file-loader": "^6.2.0",
"fs-extra": "^11.1.1",
@@ -2861,6 +3011,7 @@
"shelljs": "^0.8.5",
"tslib": "^2.6.0",
"url-loader": "^4.1.1",
+ "utility-types": "^3.10.0",
"webpack": "^5.88.1"
},
"engines": {
@@ -2876,9 +3027,10 @@
}
},
"node_modules/@docusaurus/utils-common": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.2.1.tgz",
- "integrity": "sha512-N5vadULnRLiqX2QfTjVEU3u5vo6RG2EZTdyXvJdzDOdrLCGIZAfnf/VkssinFZ922sVfaFfQ4FnStdhn5TWdVg==",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.5.2.tgz",
+ "integrity": "sha512-i0AZjHiRgJU6d7faQngIhuHKNrszpL/SHQPgF1zH4H+Ij6E9NBYGy6pkcGWToIv7IVPbs+pQLh1P3whn0gWXVg==",
+ "license": "MIT",
"dependencies": {
"tslib": "^2.6.0"
},
@@ -2895,15 +3047,18 @@
}
},
"node_modules/@docusaurus/utils-validation": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.2.1.tgz",
- "integrity": "sha512-+x7IR9hNMXi62L1YAglwd0s95fR7+EtirjTxSN4kahYRWGqOi3jlQl1EV0az/yTEvKbxVvOPcdYicGu9dk4LJw==",
- "dependencies": {
- "@docusaurus/logger": "3.2.1",
- "@docusaurus/utils": "3.2.1",
- "@docusaurus/utils-common": "3.2.1",
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.5.2.tgz",
+ "integrity": "sha512-m+Foq7augzXqB6HufdS139PFxDC5d5q2QKZy8q0qYYvGdI6nnlNsGH4cIGsgBnV7smz+mopl3g4asbSDvMV0jA==",
+ "license": "MIT",
+ "dependencies": {
+ "@docusaurus/logger": "3.5.2",
+ "@docusaurus/utils": "3.5.2",
+ "@docusaurus/utils-common": "3.5.2",
+ "fs-extra": "^11.2.0",
"joi": "^17.9.2",
"js-yaml": "^4.1.0",
+ "lodash": "^4.17.21",
"tslib": "^2.6.0"
},
"engines": {
@@ -2920,9 +3075,10 @@
}
},
"node_modules/@easyops-cn/docusaurus-search-local": {
- "version": "0.40.1",
- "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.40.1.tgz",
- "integrity": "sha512-4HMFZMpKKdd5qq1nFB8cvrAkgzZ1kNxphVciI64YHtmDYGIthVGZVG6+Ci7AAhzCR+ixLJkYwtVekvuMLjr2ZQ==",
+ "version": "0.44.5",
+ "resolved": "https://registry.npmjs.org/@easyops-cn/docusaurus-search-local/-/docusaurus-search-local-0.44.5.tgz",
+ "integrity": "sha512-jT3wuYVzRoeB1gea+2iDtOMme0fD2h3M8HDVgs3garITO6vRxvEraFRVlYkfjLN9BkmzjMlz9nn7MI4qIx8utw==",
+ "license": "MIT",
"dependencies": {
"@docusaurus/plugin-content-docs": "^2 || ^3",
"@docusaurus/theme-translations": "^2 || ^3",
@@ -2931,7 +3087,7 @@
"@docusaurus/utils-validation": "^2 || ^3",
"@easyops-cn/autocomplete.js": "^0.38.1",
"@node-rs/jieba": "^1.6.0",
- "cheerio": "^1.0.0-rc.3",
+ "cheerio": "^1.0.0",
"clsx": "^1.1.1",
"debug": "^4.2.0",
"fs-extra": "^10.0.0",
@@ -2950,6 +3106,31 @@
"react-dom": "^16.14.0 || 17 || ^18"
}
},
+ "node_modules/@easyops-cn/docusaurus-search-local/node_modules/cheerio": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
+ "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
+ "license": "MIT",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.1.0",
+ "encoding-sniffer": "^0.2.0",
+ "htmlparser2": "^9.1.0",
+ "parse5": "^7.1.2",
+ "parse5-htmlparser2-tree-adapter": "^7.0.0",
+ "parse5-parser-stream": "^7.1.2",
+ "undici": "^6.19.5",
+ "whatwg-mimetype": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18.17"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
"node_modules/@easyops-cn/docusaurus-search-local/node_modules/clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
@@ -2971,6 +3152,25 @@
"node": ">=12"
}
},
+ "node_modules/@easyops-cn/docusaurus-search-local/node_modules/htmlparser2": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
+ "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.1.0",
+ "entities": "^4.5.0"
+ }
+ },
"node_modules/@emnapi/core": {
"version": "0.45.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-0.45.0.tgz",
@@ -3144,6 +3344,7 @@
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "license": "MIT",
"dependencies": {
"@sinclair/typebox": "^0.27.8"
},
@@ -3155,6 +3356,7 @@
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
"integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+ "license": "MIT",
"dependencies": {
"@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
@@ -3259,9 +3461,10 @@
}
},
"node_modules/@mdx-js/react": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.0.tgz",
- "integrity": "sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz",
+ "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==",
+ "license": "MIT",
"dependencies": {
"@types/mdx": "^2.0.0"
},
@@ -3618,7 +3821,8 @@
"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=="
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "license": "MIT"
},
"node_modules/@sindresorhus/is": {
"version": "4.6.0",
@@ -3642,11 +3846,12 @@
}
},
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz",
- "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
+ "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==",
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3660,6 +3865,7 @@
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz",
"integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==",
+ "license": "MIT",
"engines": {
"node": ">=14"
},
@@ -3675,6 +3881,7 @@
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz",
"integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==",
+ "license": "MIT",
"engines": {
"node": ">=14"
},
@@ -3687,11 +3894,12 @@
}
},
"node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz",
- "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz",
+ "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==",
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3702,11 +3910,12 @@
}
},
"node_modules/@svgr/babel-plugin-svg-dynamic-title": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz",
- "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz",
+ "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==",
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3717,11 +3926,12 @@
}
},
"node_modules/@svgr/babel-plugin-svg-em-dimensions": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz",
- "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz",
+ "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==",
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3732,11 +3942,12 @@
}
},
"node_modules/@svgr/babel-plugin-transform-react-native-svg": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz",
- "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz",
+ "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==",
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3747,9 +3958,10 @@
}
},
"node_modules/@svgr/babel-plugin-transform-svg-component": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz",
- "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz",
+ "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==",
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -3762,21 +3974,22 @@
}
},
"node_modules/@svgr/babel-preset": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz",
- "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz",
+ "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==",
+ "license": "MIT",
"dependencies": {
- "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1",
- "@svgr/babel-plugin-remove-jsx-attribute": "*",
- "@svgr/babel-plugin-remove-jsx-empty-expression": "*",
- "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1",
- "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1",
- "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1",
- "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1",
- "@svgr/babel-plugin-transform-svg-component": "^6.5.1"
+ "@svgr/babel-plugin-add-jsx-attribute": "8.0.0",
+ "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0",
+ "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0",
+ "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0",
+ "@svgr/babel-plugin-svg-dynamic-title": "8.0.0",
+ "@svgr/babel-plugin-svg-em-dimensions": "8.0.0",
+ "@svgr/babel-plugin-transform-react-native-svg": "8.1.0",
+ "@svgr/babel-plugin-transform-svg-component": "8.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3787,18 +4000,19 @@
}
},
"node_modules/@svgr/core": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz",
- "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
+ "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
+ "license": "MIT",
"dependencies": {
- "@babel/core": "^7.19.6",
- "@svgr/babel-preset": "^6.5.1",
- "@svgr/plugin-jsx": "^6.5.1",
+ "@babel/core": "^7.21.3",
+ "@svgr/babel-preset": "8.1.0",
"camelcase": "^6.2.0",
- "cosmiconfig": "^7.0.1"
+ "cosmiconfig": "^8.1.3",
+ "snake-case": "^3.0.4"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3806,15 +4020,16 @@
}
},
"node_modules/@svgr/hast-util-to-babel-ast": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz",
- "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz",
+ "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==",
+ "license": "MIT",
"dependencies": {
- "@babel/types": "^7.20.0",
+ "@babel/types": "^7.21.3",
"entities": "^4.4.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3822,37 +4037,39 @@
}
},
"node_modules/@svgr/plugin-jsx": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz",
- "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz",
+ "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==",
+ "license": "MIT",
"dependencies": {
- "@babel/core": "^7.19.6",
- "@svgr/babel-preset": "^6.5.1",
- "@svgr/hast-util-to-babel-ast": "^6.5.1",
+ "@babel/core": "^7.21.3",
+ "@svgr/babel-preset": "8.1.0",
+ "@svgr/hast-util-to-babel-ast": "8.0.0",
"svg-parser": "^2.0.4"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/gregberge"
},
"peerDependencies": {
- "@svgr/core": "^6.0.0"
+ "@svgr/core": "*"
}
},
"node_modules/@svgr/plugin-svgo": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz",
- "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz",
+ "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==",
+ "license": "MIT",
"dependencies": {
- "cosmiconfig": "^7.0.1",
- "deepmerge": "^4.2.2",
- "svgo": "^2.8.0"
+ "cosmiconfig": "^8.1.3",
+ "deepmerge": "^4.3.1",
+ "svgo": "^3.0.2"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3863,21 +4080,22 @@
}
},
"node_modules/@svgr/webpack": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz",
- "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz",
+ "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==",
+ "license": "MIT",
"dependencies": {
- "@babel/core": "^7.19.6",
- "@babel/plugin-transform-react-constant-elements": "^7.18.12",
- "@babel/preset-env": "^7.19.4",
+ "@babel/core": "^7.21.3",
+ "@babel/plugin-transform-react-constant-elements": "^7.21.3",
+ "@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
- "@babel/preset-typescript": "^7.18.6",
- "@svgr/core": "^6.5.1",
- "@svgr/plugin-jsx": "^6.5.1",
- "@svgr/plugin-svgo": "^6.5.1"
+ "@babel/preset-typescript": "^7.21.0",
+ "@svgr/core": "8.1.0",
+ "@svgr/plugin-jsx": "8.1.0",
+ "@svgr/plugin-svgo": "8.1.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
},
"funding": {
"type": "github",
@@ -3899,6 +4117,7 @@
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
+ "license": "ISC",
"engines": {
"node": ">=10.13.0"
}
@@ -3962,24 +4181,6 @@
"@types/ms": "*"
}
},
- "node_modules/@types/eslint": {
- "version": "8.56.2",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
- "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==",
- "dependencies": {
- "@types/estree": "*",
- "@types/json-schema": "*"
- }
- },
- "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==",
- "dependencies": {
- "@types/eslint": "*",
- "@types/estree": "*"
- }
- },
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
@@ -4018,7 +4219,8 @@
"node_modules/@types/gtag.js": {
"version": "0.0.12",
"resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz",
- "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg=="
+ "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==",
+ "license": "MIT"
},
"node_modules/@types/hast": {
"version": "3.0.4",
@@ -4059,12 +4261,14 @@
"node_modules/@types/istanbul-lib-coverage": {
"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=="
+ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
+ "license": "MIT"
},
"node_modules/@types/istanbul-lib-report": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
"integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
+ "license": "MIT",
"dependencies": {
"@types/istanbul-lib-coverage": "*"
}
@@ -4073,6 +4277,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==",
+ "license": "MIT",
"dependencies": {
"@types/istanbul-lib-report": "*"
}
@@ -4194,6 +4399,7 @@
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz",
"integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==",
+ "license": "MIT",
"dependencies": {
"@types/node": "*"
}
@@ -4258,9 +4464,10 @@
}
},
"node_modules/@types/yargs": {
- "version": "17.0.32",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
- "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==",
+ "version": "17.0.33",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
+ "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==",
+ "license": "MIT",
"dependencies": {
"@types/yargs-parser": "*"
}
@@ -4268,7 +4475,8 @@
"node_modules/@types/yargs-parser": {
"version": "21.0.3",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
- "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="
+ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
+ "license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "6.20.0",
@@ -4490,9 +4698,9 @@
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
},
"node_modules/@webassemblyjs/ast": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
- "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
+ "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
"dependencies": {
"@webassemblyjs/helper-numbers": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
@@ -4509,9 +4717,9 @@
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q=="
},
"node_modules/@webassemblyjs/helper-buffer": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
- "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA=="
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
+ "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw=="
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.11.6",
@@ -4529,14 +4737,14 @@
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA=="
},
"node_modules/@webassemblyjs/helper-wasm-section": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
- "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
+ "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
"dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-buffer": "1.11.6",
+ "@webassemblyjs/ast": "1.12.1",
+ "@webassemblyjs/helper-buffer": "1.12.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.11.6"
+ "@webassemblyjs/wasm-gen": "1.12.1"
}
},
"node_modules/@webassemblyjs/ieee754": {
@@ -4561,26 +4769,26 @@
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA=="
},
"node_modules/@webassemblyjs/wasm-edit": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
- "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
+ "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==",
"dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-buffer": "1.11.6",
+ "@webassemblyjs/ast": "1.12.1",
+ "@webassemblyjs/helper-buffer": "1.12.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/helper-wasm-section": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.11.6",
- "@webassemblyjs/wasm-opt": "1.11.6",
- "@webassemblyjs/wasm-parser": "1.11.6",
- "@webassemblyjs/wast-printer": "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"
}
},
"node_modules/@webassemblyjs/wasm-gen": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
- "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
+ "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
"dependencies": {
- "@webassemblyjs/ast": "1.11.6",
+ "@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/ieee754": "1.11.6",
"@webassemblyjs/leb128": "1.11.6",
@@ -4588,22 +4796,22 @@
}
},
"node_modules/@webassemblyjs/wasm-opt": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
- "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
+ "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
"dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-buffer": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.11.6",
- "@webassemblyjs/wasm-parser": "1.11.6"
+ "@webassemblyjs/ast": "1.12.1",
+ "@webassemblyjs/helper-buffer": "1.12.1",
+ "@webassemblyjs/wasm-gen": "1.12.1",
+ "@webassemblyjs/wasm-parser": "1.12.1"
}
},
"node_modules/@webassemblyjs/wasm-parser": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
- "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
+ "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
"dependencies": {
- "@webassemblyjs/ast": "1.11.6",
+ "@webassemblyjs/ast": "1.12.1",
"@webassemblyjs/helper-api-error": "1.11.6",
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
"@webassemblyjs/ieee754": "1.11.6",
@@ -4612,11 +4820,11 @@
}
},
"node_modules/@webassemblyjs/wast-printer": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
- "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
+ "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
"dependencies": {
- "@webassemblyjs/ast": "1.11.6",
+ "@webassemblyjs/ast": "1.12.1",
"@xtuc/long": "4.2.2"
}
},
@@ -4672,10 +4880,10 @@
"node": ">=0.4.0"
}
},
- "node_modules/acorn-import-assertions": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
- "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
+ "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==",
"peerDependencies": {
"acorn": "^8"
}
@@ -4759,31 +4967,33 @@
}
},
"node_modules/algoliasearch": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.23.3.tgz",
- "integrity": "sha512-Le/3YgNvjW9zxIQMRhUHuhiUjAlKY/zsdZpfq4dlLqg6mEm0nL6yk+7f2hDOtLpxsgE4jSzDmvHL7nXdBp5feg==",
- "dependencies": {
- "@algolia/cache-browser-local-storage": "4.23.3",
- "@algolia/cache-common": "4.23.3",
- "@algolia/cache-in-memory": "4.23.3",
- "@algolia/client-account": "4.23.3",
- "@algolia/client-analytics": "4.23.3",
- "@algolia/client-common": "4.23.3",
- "@algolia/client-personalization": "4.23.3",
- "@algolia/client-search": "4.23.3",
- "@algolia/logger-common": "4.23.3",
- "@algolia/logger-console": "4.23.3",
- "@algolia/recommend": "4.23.3",
- "@algolia/requester-browser-xhr": "4.23.3",
- "@algolia/requester-common": "4.23.3",
- "@algolia/requester-node-http": "4.23.3",
- "@algolia/transporter": "4.23.3"
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz",
+ "integrity": "sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/cache-browser-local-storage": "4.24.0",
+ "@algolia/cache-common": "4.24.0",
+ "@algolia/cache-in-memory": "4.24.0",
+ "@algolia/client-account": "4.24.0",
+ "@algolia/client-analytics": "4.24.0",
+ "@algolia/client-common": "4.24.0",
+ "@algolia/client-personalization": "4.24.0",
+ "@algolia/client-search": "4.24.0",
+ "@algolia/logger-common": "4.24.0",
+ "@algolia/logger-console": "4.24.0",
+ "@algolia/recommend": "4.24.0",
+ "@algolia/requester-browser-xhr": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/requester-node-http": "4.24.0",
+ "@algolia/transporter": "4.24.0"
}
},
"node_modules/algoliasearch-helper": {
- "version": "3.18.0",
- "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.18.0.tgz",
- "integrity": "sha512-ZXvA8r6VG46V343jnIE7Tei8Xr0/9N8YhD27joC0BKxeogQyvNu7O37i510wA7FnrDjoa/tFhK90WUaBlkaqnw==",
+ "version": "3.22.5",
+ "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.22.5.tgz",
+ "integrity": "sha512-lWvhdnc+aKOKx8jyA3bsdEgHzm/sglC4cYdMG4xSQyRiPLJVJtH/IVYZG3Hp6PkTEhQqhyVYkeP9z2IlcHJsWw==",
+ "license": "MIT",
"dependencies": {
"@algolia/events": "^4.0.1"
},
@@ -4791,6 +5001,45 @@
"algoliasearch": ">= 3.1 < 6"
}
},
+ "node_modules/algoliasearch/node_modules/@algolia/client-common": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz",
+ "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/algoliasearch/node_modules/@algolia/client-search": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz",
+ "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/client-common": "4.24.0",
+ "@algolia/requester-common": "4.24.0",
+ "@algolia/transporter": "4.24.0"
+ }
+ },
+ "node_modules/algoliasearch/node_modules/@algolia/requester-browser-xhr": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz",
+ "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0"
+ }
+ },
+ "node_modules/algoliasearch/node_modules/@algolia/requester-node-http": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz",
+ "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==",
+ "license": "MIT",
+ "dependencies": {
+ "@algolia/requester-common": "4.24.0"
+ }
+ },
"node_modules/ansi-align": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
@@ -4865,7 +5114,8 @@
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
- "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "license": "MIT"
},
"node_modules/argparse": {
"version": "2.0.1",
@@ -5041,9 +5291,10 @@
}
},
"node_modules/body-parser": {
- "version": "1.20.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
- "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+ "license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
@@ -5053,7 +5304,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
- "qs": "6.11.0",
+ "qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@@ -5067,6 +5318,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -5075,6 +5327,7 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
@@ -5082,7 +5335,8 @@
"node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
},
"node_modules/bonjour-service": {
"version": "1.2.1",
@@ -5269,6 +5523,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
"integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
+ "license": "MIT",
"dependencies": {
"browserslist": "^4.0.0",
"caniuse-lite": "^1.0.0",
@@ -5542,9 +5797,10 @@
}
},
"node_modules/clsx": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
- "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -5577,7 +5833,8 @@
"node_modules/colord": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
- "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
+ "license": "MIT"
},
"node_modules/colorette": {
"version": "2.0.20",
@@ -5725,6 +5982,7 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -5751,6 +6009,7 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz",
"integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==",
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -5859,18 +6118,29 @@
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/cosmiconfig": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
- "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+ "version": "8.3.6",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
+ "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
+ "license": "MIT",
"dependencies": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.2.1",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.10.0"
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0",
+ "path-type": "^4.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
"node_modules/cross-spawn": {
@@ -5912,11 +6182,12 @@
}
},
"node_modules/css-declaration-sorter": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz",
- "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz",
+ "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==",
+ "license": "ISC",
"engines": {
- "node": "^10 || ^12 || >=14"
+ "node": "^14 || ^16 || >=18"
},
"peerDependencies": {
"postcss": "^8.0.9"
@@ -5957,16 +6228,17 @@
}
},
"node_modules/css-minimizer-webpack-plugin": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz",
- "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz",
+ "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==",
+ "license": "MIT",
"dependencies": {
- "cssnano": "^5.1.8",
- "jest-worker": "^29.1.2",
- "postcss": "^8.4.17",
- "schema-utils": "^4.0.0",
- "serialize-javascript": "^6.0.0",
- "source-map": "^0.6.1"
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "cssnano": "^6.0.1",
+ "jest-worker": "^29.4.3",
+ "postcss": "^8.4.24",
+ "schema-utils": "^4.0.1",
+ "serialize-javascript": "^6.0.1"
},
"engines": {
"node": ">= 14.15.0"
@@ -5999,14 +6271,6 @@
}
}
},
- "node_modules/css-minimizer-webpack-plugin/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==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
@@ -6023,23 +6287,16 @@
}
},
"node_modules/css-tree": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
- "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
+ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+ "license": "MIT",
"dependencies": {
- "mdn-data": "2.0.14",
- "source-map": "^0.6.1"
+ "mdn-data": "2.0.30",
+ "source-map-js": "^1.0.1"
},
"engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/css-tree/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==",
- "engines": {
- "node": ">=0.10.0"
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
"node_modules/css-what": {
@@ -6065,108 +6322,135 @@
}
},
"node_modules/cssnano": {
- "version": "5.1.15",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz",
- "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz",
+ "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==",
+ "license": "MIT",
"dependencies": {
- "cssnano-preset-default": "^5.2.14",
- "lilconfig": "^2.0.3",
- "yaml": "^1.10.2"
+ "cssnano-preset-default": "^6.1.2",
+ "lilconfig": "^3.1.1"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/cssnano"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/cssnano-preset-advanced": {
- "version": "5.3.10",
- "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz",
- "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz",
+ "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==",
+ "license": "MIT",
"dependencies": {
- "autoprefixer": "^10.4.12",
- "cssnano-preset-default": "^5.2.14",
- "postcss-discard-unused": "^5.1.0",
- "postcss-merge-idents": "^5.1.1",
- "postcss-reduce-idents": "^5.2.0",
- "postcss-zindex": "^5.1.0"
+ "autoprefixer": "^10.4.19",
+ "browserslist": "^4.23.0",
+ "cssnano-preset-default": "^6.1.2",
+ "postcss-discard-unused": "^6.0.5",
+ "postcss-merge-idents": "^6.0.3",
+ "postcss-reduce-idents": "^6.0.3",
+ "postcss-zindex": "^6.0.2"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/cssnano-preset-default": {
- "version": "5.2.14",
- "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz",
- "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==",
- "dependencies": {
- "css-declaration-sorter": "^6.3.1",
- "cssnano-utils": "^3.1.0",
- "postcss-calc": "^8.2.3",
- "postcss-colormin": "^5.3.1",
- "postcss-convert-values": "^5.1.3",
- "postcss-discard-comments": "^5.1.2",
- "postcss-discard-duplicates": "^5.1.0",
- "postcss-discard-empty": "^5.1.1",
- "postcss-discard-overridden": "^5.1.0",
- "postcss-merge-longhand": "^5.1.7",
- "postcss-merge-rules": "^5.1.4",
- "postcss-minify-font-values": "^5.1.0",
- "postcss-minify-gradients": "^5.1.1",
- "postcss-minify-params": "^5.1.4",
- "postcss-minify-selectors": "^5.2.1",
- "postcss-normalize-charset": "^5.1.0",
- "postcss-normalize-display-values": "^5.1.0",
- "postcss-normalize-positions": "^5.1.1",
- "postcss-normalize-repeat-style": "^5.1.1",
- "postcss-normalize-string": "^5.1.0",
- "postcss-normalize-timing-functions": "^5.1.0",
- "postcss-normalize-unicode": "^5.1.1",
- "postcss-normalize-url": "^5.1.0",
- "postcss-normalize-whitespace": "^5.1.1",
- "postcss-ordered-values": "^5.1.3",
- "postcss-reduce-initial": "^5.1.2",
- "postcss-reduce-transforms": "^5.1.0",
- "postcss-svgo": "^5.1.0",
- "postcss-unique-selectors": "^5.1.1"
- },
- "engines": {
- "node": "^10 || ^12 || >=14.0"
- },
- "peerDependencies": {
- "postcss": "^8.2.15"
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz",
+ "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==",
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.23.0",
+ "css-declaration-sorter": "^7.2.0",
+ "cssnano-utils": "^4.0.2",
+ "postcss-calc": "^9.0.1",
+ "postcss-colormin": "^6.1.0",
+ "postcss-convert-values": "^6.1.0",
+ "postcss-discard-comments": "^6.0.2",
+ "postcss-discard-duplicates": "^6.0.3",
+ "postcss-discard-empty": "^6.0.3",
+ "postcss-discard-overridden": "^6.0.2",
+ "postcss-merge-longhand": "^6.0.5",
+ "postcss-merge-rules": "^6.1.1",
+ "postcss-minify-font-values": "^6.1.0",
+ "postcss-minify-gradients": "^6.0.3",
+ "postcss-minify-params": "^6.1.0",
+ "postcss-minify-selectors": "^6.0.4",
+ "postcss-normalize-charset": "^6.0.2",
+ "postcss-normalize-display-values": "^6.0.2",
+ "postcss-normalize-positions": "^6.0.2",
+ "postcss-normalize-repeat-style": "^6.0.2",
+ "postcss-normalize-string": "^6.0.2",
+ "postcss-normalize-timing-functions": "^6.0.2",
+ "postcss-normalize-unicode": "^6.1.0",
+ "postcss-normalize-url": "^6.0.2",
+ "postcss-normalize-whitespace": "^6.0.2",
+ "postcss-ordered-values": "^6.0.2",
+ "postcss-reduce-initial": "^6.1.0",
+ "postcss-reduce-transforms": "^6.0.2",
+ "postcss-svgo": "^6.0.3",
+ "postcss-unique-selectors": "^6.0.4"
+ },
+ "engines": {
+ "node": "^14 || ^16 || >=18.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.31"
}
},
"node_modules/cssnano-utils": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
- "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz",
+ "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==",
+ "license": "MIT",
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/csso": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
- "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
+ "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
+ "license": "MIT",
"dependencies": {
- "css-tree": "^1.1.2"
+ "css-tree": "~2.2.0"
},
"engines": {
- "node": ">=8.0.0"
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+ "npm": ">=7.0.0"
}
},
+ "node_modules/csso/node_modules/css-tree": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
+ "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.0.28",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/csso/node_modules/mdn-data": {
+ "version": "2.0.28",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
+ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
+ "license": "CC0-1.0"
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -6336,6 +6620,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -6352,6 +6637,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
@@ -6553,7 +6839,8 @@
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.4.749",
@@ -6588,17 +6875,43 @@
}
},
"node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
+ "node_modules/encoding-sniffer": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
+ "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "^0.6.3",
+ "whatwg-encoding": "^3.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+ }
+ },
+ "node_modules/encoding-sniffer/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/enhanced-resolve": {
- "version": "5.15.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
- "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
+ "version": "5.17.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
+ "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -7118,6 +7431,7 @@
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -7170,36 +7484,37 @@
}
},
"node_modules/express": {
- "version": "4.19.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
- "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
+ "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
+ "license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.20.2",
+ "body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "1.2.0",
+ "finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
- "merge-descriptors": "1.0.1",
+ "merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
+ "path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
- "qs": "6.11.0",
+ "qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
- "send": "0.18.0",
- "serve-static": "1.15.0",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@@ -7235,9 +7550,10 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/express/node_modules/path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ "version": "0.1.10",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
+ "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
+ "license": "MIT"
},
"node_modules/express/node_modules/range-parser": {
"version": "1.2.1",
@@ -7440,12 +7756,13 @@
}
},
"node_modules/finalhandler": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
- "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+ "license": "MIT",
"dependencies": {
"debug": "2.6.9",
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
@@ -7460,6 +7777,7 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
@@ -7467,7 +7785,8 @@
"node_modules/finalhandler/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
},
"node_modules/find-cache-dir": {
"version": "4.0.0",
@@ -7706,6 +8025,7 @@
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -8491,6 +8811,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
@@ -8578,6 +8899,7 @@
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
@@ -8672,9 +8994,10 @@
}
},
"node_modules/infima": {
- "version": "0.2.0-alpha.43",
- "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz",
- "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==",
+ "version": "0.2.0-alpha.44",
+ "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.44.tgz",
+ "integrity": "sha512-tuRkUSO/lB3rEhLJk25atwAjgLuzq070+pOW8XcvpHky/YbENnRRdPd85IBkyeTgttmOy5ah+yHYsK1HhUd4lQ==",
+ "license": "MIT",
"engines": {
"node": ">=12"
}
@@ -9012,6 +9335,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
"integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+ "license": "MIT",
"dependencies": {
"@jest/types": "^29.6.3",
"@types/node": "*",
@@ -9028,6 +9352,7 @@
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
"integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+ "license": "MIT",
"dependencies": {
"@types/node": "*",
"jest-util": "^29.7.0",
@@ -9042,6 +9367,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -9219,11 +9545,15 @@
}
},
"node_modules/lilconfig": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
- "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
+ "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/lines-and-columns": {
@@ -9279,7 +9609,8 @@
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+ "license": "MIT"
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@@ -9290,7 +9621,8 @@
"node_modules/lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="
+ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
+ "license": "MIT"
},
"node_modules/longest-streak": {
"version": "3.1.0",
@@ -9753,14 +10085,16 @@
}
},
"node_modules/mdn-data": {
- "version": "2.0.14",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
- "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+ "license": "CC0-1.0"
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -9777,9 +10111,13 @@
}
},
"node_modules/merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
"node_modules/merge-stream": {
"version": "2.0.0",
@@ -11474,11 +11812,11 @@
]
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -11489,6 +11827,7 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "license": "MIT",
"bin": {
"mime": "cli.js"
},
@@ -11689,17 +12028,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/normalize-url": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
- "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -11714,7 +12042,8 @@
"node_modules/nprogress": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
- "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
+ "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==",
+ "license": "MIT"
},
"node_modules/nth-check": {
"version": "2.1.1",
@@ -11736,9 +12065,13 @@
}
},
"node_modules/object-inspect": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
- "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -11777,6 +12110,7 @@
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
@@ -12031,6 +12365,18 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
+ "node_modules/parse5-parser-stream": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
+ "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
+ "license": "MIT",
+ "dependencies": {
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -12083,9 +12429,10 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/path-to-regexp": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
- "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz",
+ "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==",
+ "license": "MIT",
"dependencies": {
"isarray": "0.0.1"
}
@@ -12109,9 +12456,10 @@
}
},
"node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+ "license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -12206,9 +12554,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.33",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
- "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"funding": [
{
"type": "opencollective",
@@ -12223,115 +12571,127 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/postcss-calc": {
- "version": "8.2.4",
- "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz",
- "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==",
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz",
+ "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==",
+ "license": "MIT",
"dependencies": {
- "postcss-selector-parser": "^6.0.9",
+ "postcss-selector-parser": "^6.0.11",
"postcss-value-parser": "^4.2.0"
},
+ "engines": {
+ "node": "^14 || ^16 || >=18.0"
+ },
"peerDependencies": {
"postcss": "^8.2.2"
}
},
"node_modules/postcss-colormin": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz",
- "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz",
+ "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==",
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.21.4",
+ "browserslist": "^4.23.0",
"caniuse-api": "^3.0.0",
- "colord": "^2.9.1",
+ "colord": "^2.9.3",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-convert-values": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz",
- "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz",
+ "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==",
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.21.4",
+ "browserslist": "^4.23.0",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-discard-comments": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz",
- "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz",
+ "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==",
+ "license": "MIT",
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-discard-duplicates": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
- "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz",
+ "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==",
+ "license": "MIT",
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-discard-empty": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
- "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz",
+ "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==",
+ "license": "MIT",
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-discard-overridden": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
- "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz",
+ "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==",
+ "license": "MIT",
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-discard-unused": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz",
- "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==",
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz",
+ "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==",
+ "license": "MIT",
"dependencies": {
- "postcss-selector-parser": "^6.0.5"
+ "postcss-selector-parser": "^6.0.16"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-loader": {
@@ -12355,136 +12715,118 @@
"webpack": "^5.0.0"
}
},
- "node_modules/postcss-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==",
- "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/postcss-merge-idents": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz",
- "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz",
+ "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==",
+ "license": "MIT",
"dependencies": {
- "cssnano-utils": "^3.1.0",
+ "cssnano-utils": "^4.0.2",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-merge-longhand": {
- "version": "5.1.7",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz",
- "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==",
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz",
+ "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0",
- "stylehacks": "^5.1.1"
+ "stylehacks": "^6.1.1"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-merge-rules": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz",
- "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==",
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz",
+ "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==",
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.21.4",
+ "browserslist": "^4.23.0",
"caniuse-api": "^3.0.0",
- "cssnano-utils": "^3.1.0",
- "postcss-selector-parser": "^6.0.5"
+ "cssnano-utils": "^4.0.2",
+ "postcss-selector-parser": "^6.0.16"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-minify-font-values": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz",
- "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz",
+ "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-minify-gradients": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz",
- "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz",
+ "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==",
+ "license": "MIT",
"dependencies": {
- "colord": "^2.9.1",
- "cssnano-utils": "^3.1.0",
+ "colord": "^2.9.3",
+ "cssnano-utils": "^4.0.2",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-minify-params": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz",
- "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz",
+ "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==",
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.21.4",
- "cssnano-utils": "^3.1.0",
+ "browserslist": "^4.23.0",
+ "cssnano-utils": "^4.0.2",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-minify-selectors": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz",
- "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==",
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz",
+ "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==",
+ "license": "MIT",
"dependencies": {
- "postcss-selector-parser": "^6.0.5"
+ "postcss-selector-parser": "^6.0.16"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-modules-extract-imports": {
@@ -12543,192 +12885,205 @@
}
},
"node_modules/postcss-normalize-charset": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
- "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz",
+ "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==",
+ "license": "MIT",
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-display-values": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz",
- "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz",
+ "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-positions": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz",
- "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz",
+ "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-repeat-style": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz",
- "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz",
+ "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-string": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz",
- "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz",
+ "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-timing-functions": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz",
- "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz",
+ "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-unicode": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz",
- "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz",
+ "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==",
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.21.4",
+ "browserslist": "^4.23.0",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-url": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz",
- "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz",
+ "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==",
+ "license": "MIT",
"dependencies": {
- "normalize-url": "^6.0.1",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-normalize-whitespace": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz",
- "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz",
+ "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-ordered-values": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz",
- "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz",
+ "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==",
+ "license": "MIT",
"dependencies": {
- "cssnano-utils": "^3.1.0",
+ "cssnano-utils": "^4.0.2",
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-reduce-idents": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz",
- "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz",
+ "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-reduce-initial": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz",
- "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz",
+ "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==",
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.21.4",
+ "browserslist": "^4.23.0",
"caniuse-api": "^3.0.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-reduce-transforms": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz",
- "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz",
+ "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-selector-parser": {
- "version": "6.0.15",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
- "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -12738,46 +13093,49 @@
}
},
"node_modules/postcss-sort-media-queries": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz",
- "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz",
+ "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==",
+ "license": "MIT",
"dependencies": {
- "sort-css-media-queries": "2.1.0"
+ "sort-css-media-queries": "2.2.0"
},
"engines": {
- "node": ">=10.0.0"
+ "node": ">=14.0.0"
},
"peerDependencies": {
- "postcss": "^8.4.16"
+ "postcss": "^8.4.23"
}
},
"node_modules/postcss-svgo": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz",
- "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz",
+ "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.2.0",
- "svgo": "^2.7.0"
+ "svgo": "^3.2.0"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >= 18"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-unique-selectors": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz",
- "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==",
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz",
+ "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==",
+ "license": "MIT",
"dependencies": {
- "postcss-selector-parser": "^6.0.5"
+ "postcss-selector-parser": "^6.0.16"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-value-parser": {
@@ -12786,14 +13144,15 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
"node_modules/postcss-zindex": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz",
- "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz",
+ "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==",
+ "license": "MIT",
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/prelude-ls": {
@@ -12823,9 +13182,10 @@
}
},
"node_modules/prism-react-renderer": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz",
- "integrity": "sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==",
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.0.tgz",
+ "integrity": "sha512-327BsVCD/unU4CNLZTWVHyUHKnsqcvj2qbPlQ8MiBE2eq2rgctjigPA1Gp9HLF83kZ20zNN6jgizHJeEsyFYOw==",
+ "license": "MIT",
"dependencies": {
"@types/prismjs": "^1.26.0",
"clsx": "^2.0.0"
@@ -12838,6 +13198,7 @@
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -12923,11 +13284,12 @@
}
},
"node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+ "license": "BSD-3-Clause",
"dependencies": {
- "side-channel": "^1.0.4"
+ "side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -12994,6 +13356,7 @@
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
@@ -13008,6 +13371,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -13099,9 +13463,10 @@
}
},
"node_modules/react": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -13228,15 +13593,16 @@
}
},
"node_modules/react-dom": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
- "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
+ "scheduler": "^0.23.2"
},
"peerDependencies": {
- "react": "^18.2.0"
+ "react": "^18.3.1"
}
},
"node_modules/react-error-overlay": {
@@ -13271,9 +13637,10 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-json-view-lite": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.3.0.tgz",
- "integrity": "sha512-aN1biKC5v4DQkmQBlZjuMFR09MKZGMPtIg+cut8zEeg2HXd6gl2gRy0n4HMacHf0dznQgo0SVXN7eT8zV3hEuQ==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz",
+ "integrity": "sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw==",
+ "license": "MIT",
"engines": {
"node": ">=14"
},
@@ -13283,12 +13650,12 @@
},
"node_modules/react-loadable": {
"name": "@docusaurus/react-loadable",
- "version": "5.5.2",
- "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz",
- "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz",
+ "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==",
+ "license": "MIT",
"dependencies": {
- "@types/react": "*",
- "prop-types": "^15.6.2"
+ "@types/react": "*"
},
"peerDependencies": {
"react": "*"
@@ -13838,9 +14205,10 @@
"integrity": "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ=="
},
"node_modules/rtlcss": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz",
- "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz",
+ "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==",
+ "license": "MIT",
"dependencies": {
"escalade": "^3.1.1",
"picocolors": "^1.0.0",
@@ -13898,7 +14266,8 @@
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
},
"node_modules/sax": {
"version": "1.3.0",
@@ -13906,9 +14275,10 @@
"integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
},
"node_modules/scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
}
@@ -13932,9 +14302,10 @@
}
},
"node_modules/search-insights": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.13.0.tgz",
- "integrity": "sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==",
+ "version": "2.17.2",
+ "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.2.tgz",
+ "integrity": "sha512-zFNpOpUO+tY2D85KrxJ+aqwnIfdEGi06UH2+xEb+Bp9Mwznmauqc9djbnBibJO5mpfUPPa8st6Sx65+vbeO45g==",
+ "license": "MIT",
"peer": true
},
"node_modules/section-matter": {
@@ -14011,9 +14382,10 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/send": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
- "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+ "license": "MIT",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
@@ -14037,6 +14409,7 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
@@ -14044,17 +14417,29 @@
"node_modules/send/node_modules/debug/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/send/node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
},
"node_modules/send/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=="
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
},
"node_modules/send/node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -14158,14 +14543,15 @@
}
},
"node_modules/serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+ "license": "MIT",
"dependencies": {
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
- "send": "0.18.0"
+ "send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -14190,7 +14576,8 @@
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
},
"node_modules/shallow-clone": {
"version": "3.0.1",
@@ -14255,6 +14642,7 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
@@ -14292,9 +14680,10 @@
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
},
"node_modules/sitemap": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.1.tgz",
- "integrity": "sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.2.tgz",
+ "integrity": "sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw==",
+ "license": "MIT",
"dependencies": {
"@types/node": "^17.0.5",
"@types/sax": "^1.2.1",
@@ -14312,7 +14701,8 @@
"node_modules/sitemap/node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
- "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="
+ "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
+ "license": "MIT"
},
"node_modules/skin-tone": {
"version": "2.0.0",
@@ -14333,6 +14723,16 @@
"node": ">=8"
}
},
+ "node_modules/snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@@ -14344,9 +14744,10 @@
}
},
"node_modules/sort-css-media-queries": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz",
- "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz",
+ "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==",
+ "license": "MIT",
"engines": {
"node": ">= 6.3.0"
}
@@ -14360,9 +14761,10 @@
}
},
"node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
@@ -14437,16 +14839,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/stable": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
- "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
- "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility"
- },
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -14578,18 +14975,19 @@
}
},
"node_modules/stylehacks": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
- "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==",
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz",
+ "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==",
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.21.4",
- "postcss-selector-parser": "^6.0.4"
+ "browserslist": "^4.23.0",
+ "postcss-selector-parser": "^6.0.16"
},
"engines": {
- "node": "^10 || ^12 || >=14.0"
+ "node": "^14 || ^16 || >=18.0"
},
"peerDependencies": {
- "postcss": "^8.2.15"
+ "postcss": "^8.4.31"
}
},
"node_modules/supports-color": {
@@ -14617,99 +15015,43 @@
"node_modules/svg-parser": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
- "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ=="
+ "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==",
+ "license": "MIT"
},
"node_modules/svgo": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
- "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz",
+ "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==",
+ "license": "MIT",
"dependencies": {
"@trysound/sax": "0.2.0",
"commander": "^7.2.0",
- "css-select": "^4.1.3",
- "css-tree": "^1.1.3",
- "csso": "^4.2.0",
- "picocolors": "^1.0.0",
- "stable": "^0.1.8"
+ "css-select": "^5.1.0",
+ "css-tree": "^2.3.1",
+ "css-what": "^6.1.0",
+ "csso": "^5.0.5",
+ "picocolors": "^1.0.0"
},
"bin": {
"svgo": "bin/svgo"
},
"engines": {
- "node": ">=10.13.0"
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/svgo"
}
},
"node_modules/svgo/node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "license": "MIT",
"engines": {
"node": ">= 10"
}
},
- "node_modules/svgo/node_modules/css-select": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
- "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
- "dependencies": {
- "boolbase": "^1.0.0",
- "css-what": "^6.0.1",
- "domhandler": "^4.3.1",
- "domutils": "^2.8.0",
- "nth-check": "^2.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/fb55"
- }
- },
- "node_modules/svgo/node_modules/dom-serializer": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
- "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
- "dependencies": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.2.0",
- "entities": "^2.0.0"
- },
- "funding": {
- "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
- }
- },
- "node_modules/svgo/node_modules/domhandler": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
- "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
- "dependencies": {
- "domelementtype": "^2.2.0"
- },
- "engines": {
- "node": ">= 4"
- },
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
- }
- },
- "node_modules/svgo/node_modules/domutils": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
- "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
- "dependencies": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.2.0",
- "domhandler": "^4.2.0"
- },
- "funding": {
- "url": "https://github.com/fb55/domutils?sponsor=1"
- }
- },
- "node_modules/svgo/node_modules/entities": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
- "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
@@ -14888,6 +15230,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
"engines": {
"node": ">=0.6"
}
@@ -14983,6 +15326,7 @@
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "license": "MIT",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
@@ -14995,6 +15339,7 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -15003,6 +15348,7 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
@@ -15019,9 +15365,10 @@
}
},
"node_modules/typescript": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
+ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
+ "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -15030,6 +15377,15 @@
"node": ">=14.17"
}
},
+ "node_modules/undici": {
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz",
+ "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.17"
+ }
+ },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -15211,6 +15567,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -15508,9 +15865,9 @@
}
},
"node_modules/watchpack": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
- "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
+ "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -15537,25 +15894,24 @@
}
},
"node_modules/webpack": {
- "version": "5.90.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.0.tgz",
- "integrity": "sha512-bdmyXRCXeeNIePv6R6tGPyy20aUobw4Zy8r0LUS2EWO+U+Ke/gYDgsCh7bl5rB6jPpr4r0SZa6dPxBxLooDT3w==",
+ "version": "5.94.0",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
+ "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
"dependencies": {
- "@types/eslint-scope": "^3.7.3",
"@types/estree": "^1.0.5",
- "@webassemblyjs/ast": "^1.11.5",
- "@webassemblyjs/wasm-edit": "^1.11.5",
- "@webassemblyjs/wasm-parser": "^1.11.5",
+ "@webassemblyjs/ast": "^1.12.1",
+ "@webassemblyjs/wasm-edit": "^1.12.1",
+ "@webassemblyjs/wasm-parser": "^1.12.1",
"acorn": "^8.7.1",
- "acorn-import-assertions": "^1.9.0",
+ "acorn-import-attributes": "^1.9.5",
"browserslist": "^4.21.10",
"chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^5.15.0",
+ "enhanced-resolve": "^5.17.1",
"es-module-lexer": "^1.2.1",
"eslint-scope": "5.1.1",
"events": "^3.2.0",
"glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.2.9",
+ "graceful-fs": "^4.2.11",
"json-parse-even-better-errors": "^2.3.1",
"loader-runner": "^4.2.0",
"mime-types": "^2.1.27",
@@ -15563,7 +15919,7 @@
"schema-utils": "^3.2.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.3.10",
- "watchpack": "^2.4.0",
+ "watchpack": "^2.4.1",
"webpack-sources": "^3.2.3"
},
"bin": {
@@ -15866,6 +16222,39 @@
"node": ">=0.8.0"
}
},
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-encoding/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/docs/package.json b/docs/package.json
index e82a99814f..b9078b15ce 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -15,25 +15,25 @@
"typecheck": "tsc"
},
"dependencies": {
- "@docusaurus/core": "^3.2.1",
- "@docusaurus/preset-classic": "^3.2.1",
- "@easyops-cn/docusaurus-search-local": "^0.40.1",
- "@mdx-js/react": "^3.0.0",
- "clsx": "^2.0.0",
- "prism-react-renderer": "^2.3.0",
+ "@docusaurus/core": "^3.5.2",
+ "@docusaurus/preset-classic": "^3.5.2",
+ "@easyops-cn/docusaurus-search-local": "^0.44.5",
+ "@mdx-js/react": "^3.0.1",
+ "clsx": "^2.1.1",
+ "prism-react-renderer": "^2.4.0",
"raw-loader": "^4.0.2",
- "react": "^18.0.0",
- "react-dom": "^18.0.0"
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
},
"devDependencies": {
- "@docusaurus/eslint-plugin": "^3.2.1",
- "@docusaurus/module-type-aliases": "^3.2.1",
- "@docusaurus/tsconfig": "^3.2.1",
- "@docusaurus/types": "^3.2.1",
+ "@docusaurus/eslint-plugin": "^3.5.2",
+ "@docusaurus/module-type-aliases": "^3.5.2",
+ "@docusaurus/tsconfig": "^3.5.2",
+ "@docusaurus/types": "^3.5.2",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"eslint": "^8.56.0",
- "typescript": "~5.2.2"
+ "typescript": "~5.6.2"
},
"browserslist": {
"production": [
diff --git a/docs/sidebars.ts b/docs/sidebars.ts
index 35442be736..126df5d848 100644
--- a/docs/sidebars.ts
+++ b/docs/sidebars.ts
@@ -76,6 +76,7 @@ const sidebars: SidebarsConfig = {
'guides/database-backup',
'guides/profiles',
'guides/object-storage',
+ 'guides/sso',
'guides/check',
'guides/resource-manager',
'guides/managing-api-tokens',
diff --git a/frontend/app/.eslintignore b/frontend/app/.eslintignore
deleted file mode 100644
index 280b20d9e6..0000000000
--- a/frontend/app/.eslintignore
+++ /dev/null
@@ -1,3 +0,0 @@
-dist
-node_modules
-playwright-report
diff --git a/frontend/app/.eslintrc b/frontend/app/.eslintrc
deleted file mode 100644
index 81da3d72ac..0000000000
--- a/frontend/app/.eslintrc
+++ /dev/null
@@ -1,78 +0,0 @@
-{
- "env": {
- "browser": true,
- "node": true,
- "es2021": true
- },
- "settings": {
- "react": {
- "version": "detect"
- }
- },
- "extends": [
- "eslint:recommended",
- "plugin:react/recommended",
- "plugin:cypress/recommended",
- // "plugin:prettier/recommended",
- "prettier"
- ],
- "parser": "@typescript-eslint/parser",
- "plugins": [
- "@typescript-eslint",
- "unused-imports"
- ],
- "ignorePatterns": [
- "tsconfig.json"
- ],
- "rules": {
- "react/prop-types": "off",
- "quotes": [
- "error",
- "double",
- {
- "avoidEscape": true
- }
- ],
- "array-bracket-spacing": [
- "error",
- "never"
- ],
- "no-return-assign": [
- 0
- ],
- "no-underscore-dangle": [
- 0
- ],
- "no-tabs": [
- 0
- ],
- "no-confusing-arrow": [
- 0
- ],
- "no-case-declarations": [
- 0
- ],
- "react/display-name": [
- 0
- ],
- "import/no-relative-packages": [
- 0
- ],
- "react/react-in-jsx-scope": "off",
- "@typescript-eslint/no-unused-vars": [
- "error",
- {
- "ignoreRestSiblings": true
- }
- ],
- "no-unused-vars": [
- "error",
- {
- "ignoreRestSiblings": true
- }
- ],
- "unused-imports/no-unused-imports-ts": 2,
- "semi": "error",
- "no-trailing-spaces": "error"
- }
-}
\ No newline at end of file
diff --git a/frontend/app/.prettierignore b/frontend/app/.prettierignore
deleted file mode 100644
index d97329607c..0000000000
--- a/frontend/app/.prettierignore
+++ /dev/null
@@ -1,3 +0,0 @@
-tsconfig.json
-dist
-playwright-report
diff --git a/frontend/app/.prettierrc.json b/frontend/app/.prettierrc.json
deleted file mode 100644
index 54bed9944e..0000000000
--- a/frontend/app/.prettierrc.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "semi": true,
- "tabWidth": 2,
- "printWidth": 100,
- "singleQuote": false,
- "trailingComma": "es5",
- "bracketSameLine": true
-}
diff --git a/frontend/app/biome.json b/frontend/app/biome.json
new file mode 100644
index 0000000000..27a91dd865
--- /dev/null
+++ b/frontend/app/biome.json
@@ -0,0 +1,122 @@
+{
+ "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json",
+ "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
+ "files": {
+ "ignoreUnknown": false,
+ "ignore": [
+ "./coverage",
+ "./dist",
+ "./playwright-report",
+ "./src/generated",
+ "./test-results",
+ "./tests/e2e/.auth"
+ ]
+ },
+ "formatter": {
+ "enabled": true,
+ "useEditorconfig": true,
+ "formatWithErrors": false,
+ "indentStyle": "space",
+ "indentWidth": 2,
+ "lineEnding": "lf",
+ "lineWidth": 100,
+ "attributePosition": "auto",
+ "bracketSpacing": true
+ },
+ "organizeImports": { "enabled": true },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "all": true,
+ "a11y": {
+ "noSvgWithoutTitle": "off",
+ "useAriaPropsForRole": "off",
+ "useButtonType": "off",
+ "useKeyWithClickEvents": "off",
+ "useSemanticElements": "off"
+ },
+ "complexity": {
+ "noBannedTypes": "off",
+ "noExcessiveCognitiveComplexity": "off",
+ "noForEach": "off",
+ "noUselessFragments": "off",
+ "noUselessSwitchCase": "off",
+ "noUselessThisAlias": "off",
+ "useArrowFunction": "off",
+ "useDateNow": "off",
+ "useOptionalChain": "off",
+ "useSimplifiedLogicExpression": "off"
+ },
+ "correctness": {
+ "noSwitchDeclarations": "off",
+ "noUndeclaredDependencies": "off",
+ "noUndeclaredVariables": "off",
+ "noUnusedFunctionParameters": "off",
+ "noUnusedImports": "off",
+ "noUnusedVariables": "off",
+ "useExhaustiveDependencies": "off",
+ "useHookAtTopLevel": "off",
+ "useImportExtensions": "off"
+ },
+ "performance": {
+ "noAccumulatingSpread": "off",
+ "useTopLevelRegex": "off"
+ },
+ "style": {
+ "noArguments": "off",
+ "noDefaultExport": "off",
+ "noImplicitBoolean": "off",
+ "noInferrableTypes": "off",
+ "noNamespace": "off",
+ "noNamespaceImport": "off",
+ "noNegationElse": "off",
+ "noNonNullAssertion": "off",
+ "noUselessElse": "off",
+ "useBlockStatements": "off",
+ "useConsistentArrayType": "off",
+ "useConsistentBuiltinInstantiation": "off",
+ "useConst": "off",
+ "useDefaultSwitchClause": "off",
+ "useEnumInitializers": "off",
+ "useExplicitLengthCheck": "off",
+ "useFilenamingConvention": "off",
+ "useImportType": "off",
+ "useNamingConvention": "off",
+ "useNumberNamespace": "off",
+ "useSelfClosingElements": "off",
+ "useShorthandArrayType": "off",
+ "useSingleCaseStatement": "off",
+ "useTemplate": "off"
+ },
+ "suspicious": {
+ "noArrayIndexKey": "off",
+ "noAssignInExpressions": "off",
+ "noConsole": "off",
+ "noConsoleLog": "off",
+ "noDoubleEquals": "off",
+ "noEmptyBlock": "off",
+ "noEmptyBlockStatements": "off",
+ "noEvolvingTypes": "off",
+ "noExplicitAny": "off",
+ "noExportsInTest": "off",
+ "noGlobalIsNan": "off",
+ "noImplicitAnyLet": "off",
+ "noReactSpecificProps": "off",
+ "useAwait": "off"
+ }
+ }
+ },
+ "javascript": {
+ "formatter": {
+ "jsxQuoteStyle": "double",
+ "quoteProperties": "asNeeded",
+ "trailingCommas": "es5",
+ "semicolons": "always",
+ "arrowParentheses": "always",
+ "bracketSameLine": false,
+ "quoteStyle": "double",
+ "attributePosition": "auto",
+ "bracketSpacing": true
+ }
+ }
+}
diff --git a/frontend/app/cypress/support/component.tsx b/frontend/app/cypress/support/component.tsx
index 976faec040..e603bdff7a 100644
--- a/frontend/app/cypress/support/component.tsx
+++ b/frontend/app/cypress/support/component.tsx
@@ -60,7 +60,8 @@ Cypress.Commands.add("mount", (component, options = {}) => {
options={{
searchStringToObject: queryString.parse,
objectToSearchString: queryString.stringify,
- }}>
+ }}
+ >
{component}
diff --git a/frontend/app/index.html b/frontend/app/index.html
index 9c948e45bf..3492d9dcbc 100644
--- a/frontend/app/index.html
+++ b/frontend/app/index.html
@@ -14,9 +14,7 @@
-
+
Infrahub
diff --git a/frontend/app/package-lock.json b/frontend/app/package-lock.json
index e3ca7b8ecd..b992fc2364 100644
--- a/frontend/app/package-lock.json
+++ b/frontend/app/package-lock.json
@@ -18,8 +18,8 @@
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.3",
"@hookform/error-message": "^2.0.1",
- "@iconify-icon/react": "^2.0.1",
- "@iconify-json/mdi": "^1.1.64",
+ "@iconify-icon/react": "^2.1.0",
+ "@iconify-json/mdi": "^1.2.0",
"@popperjs/core": "^2.11.8",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
@@ -36,12 +36,13 @@
"clsx": "^2.1.0",
"cm6-graphql": "^0.0.14",
"cm6-theme-basic-light": "^0.2.0",
+ "cmdk": "^1.0.0",
"cross-fetch": "^4.0.0",
"date-fns": "^3.6.0",
"graphiql": "^3.1.2",
"graphql": "^16.8.1",
"handlebars": "^4.7.8",
- "jotai": "^2.7.2",
+ "jotai": "^2.10.0",
"json-to-graphql-query": "^2.2.5",
"prismjs": "^1.29.0",
"query-string": "^9.0.0",
@@ -69,13 +70,13 @@
"unidiff": "^1.0.4",
"use-query-params": "^2.2.1",
"vite": "^5.2.8",
- "vite-tsconfig-paths": "^4.3.2",
- "web-vitals": "^2.1.4"
+ "vite-tsconfig-paths": "^4.3.2"
},
"devDependencies": {
+ "@biomejs/biome": "1.9.3",
"@graphql-codegen/cli": "^5.0.2",
"@graphql-codegen/typescript": "^4.0.9",
- "@playwright/test": "^1.47.0",
+ "@playwright/test": "^1.47.2",
"@testing-library/react": "^14.2.2",
"@types/loadable__component": "^5.13.9",
"@types/node": "^20.12.3",
@@ -86,42 +87,19 @@
"@types/react-dom": "^18.2.23",
"@types/react-test-renderer": "^18.0.7",
"@types/sha1": "^1.1.5",
- "@typescript-eslint/eslint-plugin": "^7.16.0",
"@vitest/coverage-v8": "^1.4.0",
- "cypress": "^13.7.2",
- "eslint": "^8.57.0",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-cypress": "^2.15.1",
- "eslint-plugin-import": "^2.29.1",
- "eslint-plugin-n": "^16.6.2",
- "eslint-plugin-promise": "^6.1.1",
- "eslint-plugin-react": "^7.34.1",
- "eslint-plugin-unused-imports": "^3.2.0",
+ "cypress": "^13.15.0",
"husky": "^8.0.3",
"jsdom": "^24.0.0",
"lint-staged": "^15.2.10",
"openapi-typescript": "^7.0.2",
"postcss": "^8.4.23",
- "prettier": "2.8.8",
- "prettier-eslint": "^16.3.0",
- "pretty-quick": "^3.1.3",
"react-test-renderer": "^18.2.0",
"tailwindcss": "^3.4.3",
- "ts-node": "^10.9.2",
"typescript": "^5.5.3",
- "typescript-eslint": "^7.16.0",
"vitest": "^1.4.0"
}
},
- "node_modules/@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
@@ -2276,6 +2254,170 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "node_modules/@biomejs/biome": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.3.tgz",
+ "integrity": "sha512-POjAPz0APAmX33WOQFGQrwLvlu7WLV4CFJMlB12b6ZSg+2q6fYu9kZwLCOA+x83zXfcPd1RpuWOKJW0GbBwLIQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT OR Apache-2.0",
+ "bin": {
+ "biome": "bin/biome"
+ },
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/biome"
+ },
+ "optionalDependencies": {
+ "@biomejs/cli-darwin-arm64": "1.9.3",
+ "@biomejs/cli-darwin-x64": "1.9.3",
+ "@biomejs/cli-linux-arm64": "1.9.3",
+ "@biomejs/cli-linux-arm64-musl": "1.9.3",
+ "@biomejs/cli-linux-x64": "1.9.3",
+ "@biomejs/cli-linux-x64-musl": "1.9.3",
+ "@biomejs/cli-win32-arm64": "1.9.3",
+ "@biomejs/cli-win32-x64": "1.9.3"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.3.tgz",
+ "integrity": "sha512-QZzD2XrjJDUyIZK+aR2i5DDxCJfdwiYbUKu9GzkCUJpL78uSelAHAPy7m0GuPMVtF/Uo+OKv97W3P9nuWZangQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.3.tgz",
+ "integrity": "sha512-vSCoIBJE0BN3SWDFuAY/tRavpUtNoqiceJ5PrU3xDfsLcm/U6N93JSM0M9OAiC/X7mPPfejtr6Yc9vSgWlEgVw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.3.tgz",
+ "integrity": "sha512-vJkAimD2+sVviNTbaWOGqEBy31cW0ZB52KtpVIbkuma7PlfII3tsLhFa+cwbRAcRBkobBBhqZ06hXoZAN8NODQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64-musl": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.3.tgz",
+ "integrity": "sha512-VBzyhaqqqwP3bAkkBrhVq50i3Uj9+RWuj+pYmXrMDgjS5+SKYGE56BwNw4l8hR3SmYbLSbEo15GcV043CDSk+Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.3.tgz",
+ "integrity": "sha512-x220V4c+romd26Mu1ptU+EudMXVS4xmzKxPVb9mgnfYlN4Yx9vD5NZraSx/onJnd3Gh/y8iPUdU5CDZJKg9COA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64-musl": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.3.tgz",
+ "integrity": "sha512-TJmnOG2+NOGM72mlczEsNki9UT+XAsMFAOo8J0me/N47EJ/vkLXxf481evfHLlxMejTY6IN8SdRSiPVLv6AHlA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.3.tgz",
+ "integrity": "sha512-lg/yZis2HdQGsycUvHWSzo9kOvnGgvtrYRgoCEwPBwwAL8/6crOp3+f47tPwI/LI1dZrhSji7PNsGKGHbwyAhw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.3.tgz",
+ "integrity": "sha512-cQMy2zanBkVLpmmxXdK6YePzmZx0s5Z7KEnwmrW54rcXK3myCNbQa09SwGZ8i/8sLw0H9F3X7K4rxVNGU8/D4Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
"node_modules/@codemirror/autocomplete": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.2.0.tgz",
@@ -2479,7 +2621,8 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
@@ -2491,17 +2634,19 @@
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@cypress/request": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz",
- "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==",
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.5.tgz",
+ "integrity": "sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
@@ -2509,14 +2654,14 @@
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "http-signature": "~1.3.6",
+ "form-data": "~4.0.0",
+ "http-signature": "~1.4.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"performance-now": "^2.1.0",
- "qs": "6.10.4",
+ "qs": "6.13.0",
"safe-buffer": "^5.1.2",
"tough-cookie": "^4.1.3",
"tunnel-agent": "^0.6.0",
@@ -2526,20 +2671,6 @@
"node": ">= 6"
}
},
- "node_modules/@cypress/request/node_modules/form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dev": true,
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 0.12"
- }
- },
"node_modules/@cypress/xvfb": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
@@ -2942,89 +3073,6 @@
"node": ">=12"
}
},
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
- }
- },
- "node_modules/@eslint-community/regexpp": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
- "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
- "dev": true,
- "engines": {
- "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "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.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/eslintrc/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": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "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",
- "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/js": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
- "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
"node_modules/@floating-ui/core": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz",
@@ -4147,45 +4195,13 @@
"react-hook-form": "^7.0.0"
}
},
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
- "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
- "dev": true,
- "dependencies": {
- "@humanwhocodes/object-schema": "^2.0.2",
- "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": "2.0.2",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
- "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
- "dev": true
- },
"node_modules/@iconify-icon/react": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@iconify-icon/react/-/react-2.0.1.tgz",
- "integrity": "sha512-1m6L2yNsSJ25k5baQRqNqh2J0w+91PwOn1WdBIR6ZTwxePbsZC8k3NNVc6m9BJObsIQdUlMA1NGj8el4tfbsVg==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@iconify-icon/react/-/react-2.1.0.tgz",
+ "integrity": "sha512-OuEsW5Y474rg3WlseLFQ0uuJjnyk1DhLN1Ire5JGjF4sF8/rNxGJDLSItEogRcKuUbL+zzuoBsaTUVVInuixRA==",
+ "license": "MIT",
"dependencies": {
- "iconify-icon": "^2.0.0"
+ "iconify-icon": "^2.1.0"
},
"funding": {
"url": "https://github.com/sponsors/cyberalien"
@@ -4195,9 +4211,10 @@
}
},
"node_modules/@iconify-json/mdi": {
- "version": "1.1.64",
- "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.1.64.tgz",
- "integrity": "sha512-zGeo5TjhNFAY6FmSDBLAzDO811t77r6v/mDi7CAL9w5eXqKez6bIjk8R9AL/RHIeq44ALP4Ozr4lMqFTkHr7ug==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.2.0.tgz",
+ "integrity": "sha512-E9/3l5Syg3wfuarorFodhn4s8YorxhH3U3U20LaNBNiqw1kFNIDWhF6HymuzAD35k7RH0OBasJ+ZUyFtVVV6eg==",
+ "license": "Apache-2.0",
"dependencies": {
"@iconify/types": "*"
}
@@ -4347,9 +4364,10 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
@@ -4630,13 +4648,13 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.47.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.0.tgz",
- "integrity": "sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==",
+ "version": "1.47.2",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.2.tgz",
+ "integrity": "sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.47.0"
+ "playwright": "1.47.2"
},
"bin": {
"playwright": "cli.js"
@@ -5972,6 +5990,7 @@
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz",
"integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -5987,10 +6006,11 @@
}
},
"node_modules/@testing-library/react": {
- "version": "14.2.2",
- "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.2.tgz",
- "integrity": "sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==",
+ "version": "14.3.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz",
+ "integrity": "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5",
"@testing-library/dom": "^9.0.0",
@@ -6016,31 +6036,36 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"node_modules/@types/aria-query": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -6188,12 +6213,6 @@
"integrity": "sha512-b7bq23s4fgBB76n34m2b3RBf6M369B0Z9uRR8aHTMd8kZISRkmDEpPD8hhpYvDFzr3bJCPES96cm3Q6qRNDbQw==",
"dev": true
},
- "node_modules/@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
- "dev": true
- },
"node_modules/@types/loadable__component": {
"version": "5.13.9",
"resolved": "https://registry.npmjs.org/@types/loadable__component/-/loadable__component-5.13.9.tgz",
@@ -6353,242 +6372,21 @@
"@types/node": "*"
}
},
- "node_modules/@typescript-eslint/eslint-plugin": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz",
- "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==",
- "dev": true,
- "dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "7.16.0",
- "@typescript-eslint/type-utils": "7.16.0",
- "@typescript-eslint/utils": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0",
- "graphemer": "^1.4.0",
- "ignore": "^5.3.1",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^1.3.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
+ "node_modules/@uiw/color-convert": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@uiw/color-convert/-/color-convert-2.1.1.tgz",
+ "integrity": "sha512-L421mBAT2NRsmYv7BQvofOEwV0iKee1upPVxMjo2NnkJWyIu4I+H1RxK9m3uT8yvcOlStZhv7BQBsFyJCGmIMg==",
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^7.0.0",
- "eslint": "^8.56.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
+ "@babel/runtime": ">=7.19.0"
}
},
- "node_modules/@typescript-eslint/parser": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz",
- "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "7.16.0",
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/typescript-estree": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.56.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz",
- "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/type-utils": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz",
- "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/typescript-estree": "7.16.0",
- "@typescript-eslint/utils": "7.16.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^1.3.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.56.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz",
- "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==",
- "dev": true,
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz",
- "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^1.3.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@typescript-eslint/utils": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz",
- "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "7.16.0",
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/typescript-estree": "7.16.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.56.0"
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz",
- "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "7.16.0",
- "eslint-visitor-keys": "^3.4.3"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@uiw/color-convert": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@uiw/color-convert/-/color-convert-2.1.1.tgz",
- "integrity": "sha512-L421mBAT2NRsmYv7BQvofOEwV0iKee1upPVxMjo2NnkJWyIu4I+H1RxK9m3uT8yvcOlStZhv7BQBsFyJCGmIMg==",
- "funding": {
- "url": "https://jaywcjlove.github.io/#/sponsor"
- },
- "peerDependencies": {
- "@babel/runtime": ">=7.19.0"
- }
- },
- "node_modules/@uiw/react-color": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@uiw/react-color/-/react-color-2.1.1.tgz",
- "integrity": "sha512-RE95rGzlOej848nK0onqxk2N+asrHpp3LEH2h7VJkcdJLOK54jccnGKdCc2seNue3zpCIcwPcR38hOeHhfJLJg==",
+ "node_modules/@uiw/react-color": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@uiw/react-color/-/react-color-2.1.1.tgz",
+ "integrity": "sha512-RE95rGzlOej848nK0onqxk2N+asrHpp3LEH2h7VJkcdJLOK54jccnGKdCc2seNue3zpCIcwPcR38hOeHhfJLJg==",
"dependencies": {
"@uiw/color-convert": "2.1.1",
"@uiw/react-color-alpha": "2.1.1",
@@ -7022,6 +6820,7 @@
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz",
"integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@vitest/spy": "1.4.0",
"@vitest/utils": "1.4.0",
@@ -7036,6 +6835,7 @@
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz",
"integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@vitest/utils": "1.4.0",
"p-limit": "^5.0.0",
@@ -7050,6 +6850,7 @@
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
"integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"yocto-queue": "^1.0.0"
},
@@ -7061,10 +6862,11 @@
}
},
"node_modules/@vitest/runner/node_modules/yocto-queue": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
- "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
+ "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12.20"
},
@@ -7077,6 +6879,7 @@
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz",
"integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"magic-string": "^0.30.5",
"pathe": "^1.1.1",
@@ -7091,6 +6894,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -7103,6 +6907,7 @@
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
@@ -7113,16 +6918,18 @@
}
},
"node_modules/@vitest/snapshot/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
+ "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/@vitest/spy": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz",
"integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"tinyspy": "^2.2.0"
},
@@ -7135,6 +6942,7 @@
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz",
"integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"diff-sequences": "^29.6.3",
"estree-walker": "^3.0.3",
@@ -7150,6 +6958,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -7162,6 +6971,7 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
}
@@ -7171,6 +6981,7 @@
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
@@ -7181,10 +6992,11 @@
}
},
"node_modules/@vitest/utils/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
+ "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/@whatwg-node/events": {
"version": "0.0.3",
@@ -7274,15 +7086,6 @@
"node": ">=0.4.0"
}
},
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
"node_modules/acorn-walk": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
@@ -7317,22 +7120,6 @@
"node": ">=8"
}
},
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
"node_modules/ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -7442,6 +7229,7 @@
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
"integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"deep-equal": "^2.0.5"
}
@@ -7462,26 +7250,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/array-includes": {
- "version": "3.1.8",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
- "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "is-string": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "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",
@@ -7491,129 +7259,6 @@
"node": ">=8"
}
},
- "node_modules/array.prototype.findlast": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
- "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.findlastindex": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
- "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flat": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
- "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flatmap": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
- "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.toreversed": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz",
- "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "node_modules/array.prototype.tosorted": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz",
- "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.5",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.22.3",
- "es-errors": "^1.1.0",
- "es-shim-unscopables": "^1.0.2"
- }
- },
- "node_modules/arraybuffer.prototype.slice": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
- "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
- "dev": true,
- "dependencies": {
- "array-buffer-byte-length": "^1.0.1",
- "call-bind": "^1.0.5",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.22.3",
- "es-errors": "^1.2.1",
- "get-intrinsic": "^1.2.3",
- "is-array-buffer": "^3.0.4",
- "is-shared-array-buffer": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -7625,6 +7270,7 @@
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"safer-buffer": "~2.1.0"
}
@@ -7648,6 +7294,7 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.8"
}
@@ -7657,6 +7304,7 @@
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "*"
}
@@ -7759,15 +7407,17 @@
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "*"
}
},
"node_modules/aws4": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
- "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
- "dev": true
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
+ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/babel-plugin-polyfill-corejs2": {
"version": "0.4.10",
@@ -7893,6 +7543,7 @@
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"tweetnacl": "^0.14.3"
}
@@ -8027,60 +7678,6 @@
"node": "*"
}
},
- "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.0.1",
- "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
- "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
- "dev": true,
- "dependencies": {
- "semver": "^7.0.0"
- }
- },
- "node_modules/builtins/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/builtins/node_modules/semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/builtins/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
@@ -8098,6 +7695,7 @@
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -8168,9 +7766,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001605",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz",
- "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==",
+ "version": "1.0.30001664",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz",
+ "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==",
"funding": [
{
"type": "opencollective",
@@ -8184,7 +7782,8 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
- ]
+ ],
+ "license": "CC-BY-4.0"
},
"node_modules/capital-case": {
"version": "1.0.4",
@@ -8201,7 +7800,8 @@
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
- "dev": true
+ "dev": true,
+ "license": "Apache-2.0"
},
"node_modules/ccount": {
"version": "2.0.1",
@@ -8213,10 +7813,11 @@
}
},
"node_modules/chai": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
- "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
+ "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.3",
@@ -8224,7 +7825,7 @@
"get-func-name": "^2.0.2",
"loupe": "^2.3.6",
"pathval": "^1.1.1",
- "type-detect": "^4.0.8"
+ "type-detect": "^4.1.0"
},
"engines": {
"node": ">=4"
@@ -8339,6 +7940,7 @@
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
"integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"get-func-name": "^2.0.2"
},
@@ -8574,6 +8176,20 @@
"@lezer/highlight": "^1.0.0"
}
},
+ "node_modules/cmdk": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz",
+ "integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-dialog": "1.0.5",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
"node_modules/codemirror": {
"version": "5.65.16",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz",
@@ -8668,6 +8284,13 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "node_modules/confbox": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz",
+ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/constant-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
@@ -8708,7 +8331,8 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/cosmiconfig": {
"version": "8.3.6",
@@ -8739,7 +8363,8 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"node_modules/crelt": {
"version": "1.0.6",
@@ -8884,13 +8509,14 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/cypress": {
- "version": "13.7.3",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.3.tgz",
- "integrity": "sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==",
+ "version": "13.15.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz",
+ "integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==",
"dev": true,
"hasInstallScript": true,
+ "license": "MIT",
"dependencies": {
- "@cypress/request": "^3.0.0",
+ "@cypress/request": "^3.0.4",
"@cypress/xvfb": "^1.2.4",
"@types/sinonjs__fake-timers": "8.1.1",
"@types/sizzle": "^2.3.2",
@@ -8929,7 +8555,7 @@
"request-progress": "^3.0.0",
"semver": "^7.5.3",
"supports-color": "^8.1.1",
- "tmp": "~0.2.1",
+ "tmp": "~0.2.3",
"untildify": "^4.0.0",
"yauzl": "^2.10.0"
},
@@ -9153,6 +8779,7 @@
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"assert-plus": "^1.0.0"
},
@@ -9173,57 +8800,6 @@
"node": ">=18"
}
},
- "node_modules/data-view-buffer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
- "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/data-view-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
- "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/data-view-byte-offset": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
- "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/dataloader": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz",
@@ -9309,10 +8885,11 @@
}
},
"node_modules/deep-eql": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
- "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz",
+ "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"type-detect": "^4.0.0"
},
@@ -9325,6 +8902,7 @@
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
"integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"array-buffer-byte-length": "^1.0.0",
"call-bind": "^1.0.5",
@@ -9352,12 +8930,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -9487,7 +9059,8 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=0.3.1"
}
@@ -9502,6 +9075,7 @@
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
@@ -9523,23 +9097,12 @@
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
},
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
"node_modules/dom-accessibility-api": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/dom-helpers": {
"version": "5.2.1",
@@ -9642,6 +9205,7 @@
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
@@ -9711,66 +9275,6 @@
"is-arrayish": "^0.2.1"
}
},
- "node_modules/es-abstract": {
- "version": "1.23.3",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
- "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
- "dev": true,
- "dependencies": {
- "array-buffer-byte-length": "^1.0.1",
- "arraybuffer.prototype.slice": "^1.0.3",
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "data-view-buffer": "^1.0.1",
- "data-view-byte-length": "^1.0.1",
- "data-view-byte-offset": "^1.0.0",
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-set-tostringtag": "^2.0.3",
- "es-to-primitive": "^1.2.1",
- "function.prototype.name": "^1.1.6",
- "get-intrinsic": "^1.2.4",
- "get-symbol-description": "^1.0.2",
- "globalthis": "^1.0.3",
- "gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.0.3",
- "has-symbols": "^1.0.3",
- "hasown": "^2.0.2",
- "internal-slot": "^1.0.7",
- "is-array-buffer": "^3.0.4",
- "is-callable": "^1.2.7",
- "is-data-view": "^1.0.1",
- "is-negative-zero": "^2.0.3",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.3",
- "is-string": "^1.0.7",
- "is-typed-array": "^1.1.13",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.13.1",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.5",
- "regexp.prototype.flags": "^1.5.2",
- "safe-array-concat": "^1.1.2",
- "safe-regex-test": "^1.0.3",
- "string.prototype.trim": "^1.2.9",
- "string.prototype.trimend": "^1.0.8",
- "string.prototype.trimstart": "^1.0.8",
- "typed-array-buffer": "^1.0.2",
- "typed-array-byte-length": "^1.0.1",
- "typed-array-byte-offset": "^1.0.2",
- "typed-array-length": "^1.0.6",
- "unbox-primitive": "^1.0.2",
- "which-typed-array": "^1.1.15"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
@@ -9797,6 +9301,7 @@
"resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
"integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.2",
"get-intrinsic": "^1.1.3",
@@ -9812,83 +9317,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/es-iterator-helpers": {
- "version": "1.0.18",
- "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz",
- "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.0",
- "es-errors": "^1.3.0",
- "es-set-tostringtag": "^2.0.3",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "globalthis": "^1.0.3",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.0.3",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.7",
- "iterator.prototype": "^1.1.2",
- "safe-array-concat": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-object-atoms": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
- "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
- "dev": true,
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-set-tostringtag": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
- "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.2.4",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-shim-unscopables": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
- "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
- "dev": true,
- "dependencies": {
- "hasown": "^2.0.0"
- }
- },
- "node_modules/es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "dev": true,
- "dependencies": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/esbuild": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
@@ -9935,325 +9363,265 @@
"node": ">=6"
}
},
- "node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
+ "node_modules/estree-util-is-identifier-name": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
+ "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==",
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/eslint": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
- "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
- "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.0",
- "@humanwhocodes/config-array": "^0.11.14",
- "@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.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.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",
- "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",
- "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.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
- "node_modules/eslint-compat-utils": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz",
- "integrity": "sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==",
- "dev": true,
- "dependencies": {
- "semver": "^7.5.4"
- },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"engines": {
- "node": ">=12"
- },
- "peerDependencies": {
- "eslint": ">=6.0.0"
+ "node": ">=0.10.0"
}
},
- "node_modules/eslint-compat-utils/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
+ "node_modules/eventemitter2": {
+ "version": "6.4.7",
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
+ "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
+ "dev": true
+ },
+ "node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/execa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+ "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
},
"engines": {
"node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
- "node_modules/eslint-compat-utils/node_modules/semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
+ "node_modules/executable": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
+ "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
"dev": true,
"dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
+ "pify": "^2.2.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=4"
}
},
- "node_modules/eslint-compat-utils/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
- "node_modules/eslint-config-prettier": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
- "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
+ "node_modules/external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
"dev": true,
- "bin": {
- "eslint-config-prettier": "bin/cli.js"
+ "dependencies": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
},
- "peerDependencies": {
- "eslint": ">=7.0.0"
+ "engines": {
+ "node": ">=4"
}
},
- "node_modules/eslint-import-resolver-node": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
- "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
+ "node_modules/external-editor/node_modules/tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"dependencies": {
- "debug": "^3.2.7",
- "is-core-module": "^2.13.0",
- "resolve": "^1.22.4"
+ "os-tmpdir": "~1.0.2"
+ },
+ "engines": {
+ "node": ">=0.6.0"
}
},
- "node_modules/eslint-import-resolver-node/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "node_modules/extract-files": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz",
+ "integrity": "sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==",
"dev": true,
- "dependencies": {
- "ms": "^2.1.1"
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jaydenseric"
}
},
- "node_modules/eslint-module-utils": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
- "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
"dev": true,
"dependencies": {
- "debug": "^3.2.7"
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
},
"engines": {
- "node": ">=4"
+ "node": ">= 10.17.0"
},
- "peerDependenciesMeta": {
- "eslint": {
- "optional": true
- }
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
}
},
- "node_modules/eslint-module-utils/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
"dev": true,
- "dependencies": {
- "ms": "^2.1.1"
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/fast-decode-uri-component": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
+ "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==",
+ "dev": true
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-equals": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz",
+ "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==",
+ "engines": {
+ "node": ">=6.0.0"
}
},
- "node_modules/eslint-plugin-cypress": {
- "version": "2.15.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz",
- "integrity": "sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w==",
- "dev": true,
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dependencies": {
- "globals": "^13.20.0"
+ "@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"
},
- "peerDependencies": {
- "eslint": ">= 3.2.1"
+ "engines": {
+ "node": ">=8.6.0"
}
},
- "node_modules/eslint-plugin-cypress/node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "node_modules/fast-querystring": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
+ "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==",
"dev": true,
"dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "fast-decode-uri-component": "^1.0.1"
}
},
- "node_modules/eslint-plugin-cypress/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/fast-url-parser": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
+ "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==",
"dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "dependencies": {
+ "punycode": "^1.3.2"
}
},
- "node_modules/eslint-plugin-es-x": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.6.0.tgz",
- "integrity": "sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==",
- "dev": true,
+ "node_modules/fastq": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz",
+ "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.1.2",
- "@eslint-community/regexpp": "^4.6.0",
- "eslint-compat-utils": "^0.5.0"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ota-meshi"
- },
- "peerDependencies": {
- "eslint": ">=8"
+ "reusify": "^1.0.4"
}
},
- "node_modules/eslint-plugin-import": {
- "version": "2.29.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
- "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
+ "node_modules/fb-watchman": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
"dev": true,
"dependencies": {
- "array-includes": "^3.1.7",
- "array.prototype.findlastindex": "^1.2.3",
- "array.prototype.flat": "^1.3.2",
- "array.prototype.flatmap": "^1.3.2",
- "debug": "^3.2.7",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.9",
- "eslint-module-utils": "^2.8.0",
- "hasown": "^2.0.0",
- "is-core-module": "^2.13.1",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.fromentries": "^2.0.7",
- "object.groupby": "^1.0.1",
- "object.values": "^1.1.7",
- "semver": "^6.3.1",
- "tsconfig-paths": "^3.15.0"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+ "bser": "2.1.1"
}
},
- "node_modules/eslint-plugin-import/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "node_modules/fbjs": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
+ "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
"dev": true,
"dependencies": {
- "ms": "^2.1.1"
+ "cross-fetch": "^3.1.5",
+ "fbjs-css-vars": "^1.0.0",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^1.0.35"
}
},
- "node_modules/eslint-plugin-import/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "node_modules/fbjs-css-vars": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
+ "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==",
+ "dev": true
+ },
+ "node_modules/fbjs/node_modules/cross-fetch": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
+ "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
"dev": true,
"dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
+ "node-fetch": "^2.6.12"
}
},
- "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==",
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
"dev": true,
"dependencies": {
- "@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": ">=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=7.0.0"
+ "pend": "~1.2.0"
}
},
- "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==",
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
"dev": true,
"dependencies": {
- "type-fest": "^0.20.2"
+ "escape-string-regexp": "^1.0.5"
},
"engines": {
"node": ">=8"
@@ -10262,517 +9630,460 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/eslint-plugin-n/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
+ "node_modules/figures/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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
"engines": {
- "node": ">=10"
+ "node": ">=0.8.0"
}
},
- "node_modules/eslint-plugin-n/node_modules/semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dev": true,
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
+ "to-regex-range": "^5.0.1"
},
"engines": {
- "node": ">=10"
+ "node": ">=8"
}
},
- "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,
+ "node_modules/filter-obj": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
+ "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==",
"engines": {
- "node": ">=10"
+ "node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/eslint-plugin-n/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/eslint-plugin-promise": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz",
- "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==",
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
"dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
+ "dependencies": {
+ "is-callable": "^1.1.3"
}
},
- "node_modules/eslint-plugin-react": {
- "version": "7.34.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz",
- "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==",
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
"dev": true,
- "dependencies": {
- "array-includes": "^3.1.7",
- "array.prototype.findlast": "^1.2.4",
- "array.prototype.flatmap": "^1.3.2",
- "array.prototype.toreversed": "^1.1.2",
- "array.prototype.tosorted": "^1.1.3",
- "doctrine": "^2.1.0",
- "es-iterator-helpers": "^1.0.17",
- "estraverse": "^5.3.0",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.7",
- "object.fromentries": "^2.0.7",
- "object.hasown": "^1.1.3",
- "object.values": "^1.1.7",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.5",
- "semver": "^6.3.1",
- "string.prototype.matchall": "^4.0.10"
- },
+ "license": "Apache-2.0",
"engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
+ "node": "*"
}
},
- "node_modules/eslint-plugin-react/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dev": true,
"dependencies": {
- "esutils": "^2.0.2"
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
},
"engines": {
- "node": ">=0.10.0"
+ "node": ">= 6"
}
},
- "node_modules/eslint-plugin-react/node_modules/resolve": {
- "version": "2.0.0-next.5",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
- "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "engines": {
+ "node": "*"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
}
},
- "node_modules/eslint-plugin-unused-imports": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz",
- "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==",
- "dev": true,
+ "node_modules/framer-motion": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz",
+ "integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==",
"dependencies": {
- "eslint-rule-composer": "^0.3.0"
+ "@motionone/dom": "10.12.0",
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "popmotion": "11.0.3",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
},
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "optionalDependencies": {
+ "@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
- "@typescript-eslint/eslint-plugin": "6 - 7",
- "eslint": "8"
- },
- "peerDependenciesMeta": {
- "@typescript-eslint/eslint-plugin": {
- "optional": true
- }
+ "react": ">=16.8 || ^17.0.0 || ^18.0.0",
+ "react-dom": ">=16.8 || ^17.0.0 || ^18.0.0"
}
},
- "node_modules/eslint-rule-composer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz",
- "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==",
- "dev": true,
- "engines": {
- "node": ">=4.0.0"
+ "node_modules/framesync": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
+ "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "dependencies": {
+ "tslib": "^2.1.0"
}
},
- "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==",
+ "node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
"dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
+ "node": ">=10"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "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==",
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "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==",
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
- "dependencies": {
- "is-glob": "^4.0.3"
- },
"engines": {
- "node": ">=10.13.0"
+ "node": "6.* || 8.* || >= 10.*"
}
},
- "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==",
+ "node_modules/get-east-asian-width": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz",
+ "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==",
"dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
+ "license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=18"
},
"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==",
+ "node_modules/get-func-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": "*"
}
},
- "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==",
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"dev": true,
"dependencies": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": ">= 0.4"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/esquery": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
- "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.1.0"
- },
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
"engines": {
- "node": ">=0.10"
+ "node": ">=6"
}
},
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
"dependencies": {
- "estraverse": "^5.2.0"
+ "pump": "^3.0.0"
},
"engines": {
- "node": ">=4.0"
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "node_modules/getos": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
+ "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==",
"dev": true,
- "engines": {
- "node": ">=4.0"
+ "dependencies": {
+ "async": "^3.2.0"
}
},
- "node_modules/estree-util-is-identifier-name": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
- "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
}
},
- "node_modules/estree-walker": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
- "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eventemitter2": {
- "version": "6.4.7",
- "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
- "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
- "dev": true
- },
- "node_modules/eventemitter3": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
- "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
- "dev": true,
- "license": "MIT"
+ "node_modules/gitdiff-parser": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/gitdiff-parser/-/gitdiff-parser-0.3.1.tgz",
+ "integrity": "sha512-YQJnY8aew65id8okGxKCksH3efDCJ9HzV7M9rsvd65habf39Pkh4cgYJ27AaoDMqo1X98pgNJhNMrm/kpV7UVQ=="
},
- "node_modules/execa": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
- "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
- "cross-spawn": "^7.0.0",
- "get-stream": "^5.0.0",
- "human-signals": "^1.1.1",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.0",
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2",
- "strip-final-newline": "^2.0.0"
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
},
"engines": {
- "node": ">=10"
+ "node": "*"
},
"funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/executable": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
- "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
- "dev": true,
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dependencies": {
- "pify": "^2.2.0"
+ "is-glob": "^4.0.1"
},
"engines": {
- "node": ">=4"
+ "node": ">= 6"
}
},
- "node_modules/extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "node_modules/external-editor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
- "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "node_modules/global-dirs": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
+ "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
"dev": true,
"dependencies": {
- "chardet": "^0.7.0",
- "iconv-lite": "^0.4.24",
- "tmp": "^0.0.33"
+ "ini": "2.0.0"
},
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/external-editor/node_modules/tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
- "dev": true,
- "dependencies": {
- "os-tmpdir": "~1.0.2"
- },
+ "node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"engines": {
- "node": ">=0.6.0"
+ "node": ">=4"
}
},
- "node_modules/extract-files": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz",
- "integrity": "sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==",
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
"dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
"engines": {
- "node": "^12.20 || >= 14.13"
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/jaydenseric"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/extract-zip": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
- "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "node_modules/globrex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
"dev": true,
"dependencies": {
- "debug": "^4.1.1",
- "get-stream": "^5.1.0",
- "yauzl": "^2.10.0"
- },
- "bin": {
- "extract-zip": "cli.js"
- },
- "engines": {
- "node": ">= 10.17.0"
+ "get-intrinsic": "^1.1.3"
},
- "optionalDependencies": {
- "@types/yauzl": "^2.9.1"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
- "dev": true,
- "engines": [
- "node >=0.6.0"
- ]
- },
- "node_modules/fast-decode-uri-component": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
- "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==",
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true
},
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "node_modules/graphiql": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/graphiql/-/graphiql-3.1.2.tgz",
+ "integrity": "sha512-k3p2k+7ZgARdLnqMDV192VL47cTmPNn02n5ullULnBE1nv1dtJfUve+AJxaU+kU8JcbwCxSxu3qlIxuu1N3mDQ==",
+ "dependencies": {
+ "@graphiql/react": "^0.20.4",
+ "@graphiql/toolkit": "^0.9.1",
+ "graphql-language-service": "^5.2.0",
+ "markdown-it": "^12.2.0"
+ },
+ "peerDependencies": {
+ "graphql": "^15.5.0 || ^16.0.0",
+ "react": "^16.8.0 || ^17 || ^18",
+ "react-dom": "^16.8.0 || ^17 || ^18"
+ }
},
- "node_modules/fast-equals": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz",
- "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==",
+ "node_modules/graphql": {
+ "version": "16.8.1",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
+ "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
"engines": {
- "node": ">=6.0.0"
+ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
}
},
- "node_modules/fast-glob": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
- "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "node_modules/graphql-config": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-5.0.3.tgz",
+ "integrity": "sha512-BNGZaoxIBkv9yy6Y7omvsaBUHOzfFcII3UN++tpH8MGOKFPFkCPZuwx09ggANMt8FgyWP1Od8SWPmrUEZca4NQ==",
+ "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"
+ "@graphql-tools/graphql-file-loader": "^8.0.0",
+ "@graphql-tools/json-file-loader": "^8.0.0",
+ "@graphql-tools/load": "^8.0.0",
+ "@graphql-tools/merge": "^9.0.0",
+ "@graphql-tools/url-loader": "^8.0.0",
+ "@graphql-tools/utils": "^10.0.0",
+ "cosmiconfig": "^8.1.0",
+ "jiti": "^1.18.2",
+ "minimatch": "^4.2.3",
+ "string-env-interpolation": "^1.0.1",
+ "tslib": "^2.4.0"
},
"engines": {
- "node": ">=8.6.0"
+ "node": ">= 16.0.0"
+ },
+ "peerDependencies": {
+ "cosmiconfig-toml-loader": "^1.0.0",
+ "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
+ },
+ "peerDependenciesMeta": {
+ "cosmiconfig-toml-loader": {
+ "optional": true
+ }
}
},
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "node_modules/fast-querystring": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
- "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==",
+ "node_modules/graphql-config/node_modules/minimatch": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.3.tgz",
+ "integrity": "sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng==",
"dev": true,
"dependencies": {
- "fast-decode-uri-component": "^1.0.1"
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=10"
}
},
- "node_modules/fast-url-parser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
- "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==",
- "dev": true,
- "dependencies": {
- "punycode": "^1.3.2"
- }
- },
- "node_modules/fastq": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz",
- "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==",
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/fb-watchman": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
- "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
- "dev": true,
+ "node_modules/graphql-language-service": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-5.2.0.tgz",
+ "integrity": "sha512-o/ZgTS0pBxWm3hSF4+6GwiV1//DxzoLWEbS38+jqpzzy1d/QXBidwQuVYTOksclbtOJZ3KR/tZ8fi/tI6VpVMg==",
"dependencies": {
- "bser": "2.1.1"
+ "nullthrows": "^1.0.0",
+ "vscode-languageserver-types": "^3.17.1"
+ },
+ "bin": {
+ "graphql": "dist/temp-bin.js"
+ },
+ "peerDependencies": {
+ "graphql": "^15.5.0 || ^16.0.0"
}
},
- "node_modules/fbjs": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
- "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
+ "node_modules/graphql-request": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz",
+ "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==",
"dev": true,
"dependencies": {
- "cross-fetch": "^3.1.5",
- "fbjs-css-vars": "^1.0.0",
- "loose-envify": "^1.0.0",
- "object-assign": "^4.1.0",
- "promise": "^7.1.1",
- "setimmediate": "^1.0.5",
- "ua-parser-js": "^1.0.35"
+ "@graphql-typed-document-node/core": "^3.2.0",
+ "cross-fetch": "^3.1.5"
+ },
+ "peerDependencies": {
+ "graphql": "14 - 16"
}
},
- "node_modules/fbjs-css-vars": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
- "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==",
- "dev": true
- },
- "node_modules/fbjs/node_modules/cross-fetch": {
+ "node_modules/graphql-request/node_modules/cross-fetch": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
@@ -10781,444 +10092,533 @@
"node-fetch": "^2.6.12"
}
},
- "node_modules/fd-slicer": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
- "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
- "dev": true,
+ "node_modules/graphql-tag": {
+ "version": "2.12.6",
+ "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz",
+ "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==",
"dependencies": {
- "pend": "~1.2.0"
+ "tslib": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
}
},
- "node_modules/figures": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
- "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
- "dev": true,
+ "node_modules/graphql-ws": {
+ "version": "5.16.0",
+ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz",
+ "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==",
+ "devOptional": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "graphql": ">=0.11 <=16"
+ }
+ },
+ "node_modules/handlebars": {
+ "version": "4.7.8",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
+ "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
"dependencies": {
- "escape-string-regexp": "^1.0.5"
+ "minimist": "^1.2.5",
+ "neo-async": "^2.6.2",
+ "source-map": "^0.6.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
},
"engines": {
- "node": ">=8"
+ "node": ">=0.4.7"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "optionalDependencies": {
+ "uglify-js": "^3.1.4"
}
},
- "node_modules/figures/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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "node_modules/has-bigints": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+ "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
"dev": true,
- "engines": {
- "node": ">=0.8.0"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "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,
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=8"
}
},
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
"dependencies": {
- "to-regex-range": "^5.0.1"
+ "es-define-property": "^1.0.0"
},
- "engines": {
- "node": ">=8"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/filter-obj": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
- "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==",
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "dev": true,
"engines": {
- "node": ">=14.16"
+ "node": ">= 0.4"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "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==",
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
"engines": {
- "node": ">=10"
+ "node": ">= 0.4"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"dependencies": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
+ "has-symbols": "^1.0.3"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/flatted": {
- "version": "3.2.9",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
- "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
- "dev": true
- },
- "node_modules/for-each": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "dev": true,
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dependencies": {
- "is-callable": "^1.1.3"
- }
- },
- "node_modules/forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
- "dev": true,
+ "function-bind": "^1.1.2"
+ },
"engines": {
- "node": "*"
+ "node": ">= 0.4"
}
},
- "node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dev": true,
+ "node_modules/hast-util-to-jsx-runtime": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz",
+ "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==",
"dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
+ "@types/estree": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/unist": "^3.0.0",
+ "comma-separated-tokens": "^2.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-is-identifier-name": "^3.0.0",
+ "hast-util-whitespace": "^3.0.0",
+ "mdast-util-mdx-expression": "^2.0.0",
+ "mdast-util-mdx-jsx": "^3.0.0",
+ "mdast-util-mdxjs-esm": "^2.0.0",
+ "property-information": "^6.0.0",
+ "space-separated-tokens": "^2.0.0",
+ "style-to-object": "^1.0.0",
+ "unist-util-position": "^5.0.0",
+ "vfile-message": "^4.0.0"
},
- "engines": {
- "node": ">= 6"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/fraction.js": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
- "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
- "engines": {
- "node": "*"
+ "node_modules/hast-util-whitespace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
+ "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
+ "dependencies": {
+ "@types/hast": "^3.0.0"
},
"funding": {
- "type": "patreon",
- "url": "https://github.com/sponsors/rawify"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/framer-motion": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz",
- "integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==",
- "dependencies": {
- "@motionone/dom": "10.12.0",
- "framesync": "6.0.1",
- "hey-listen": "^1.0.8",
- "popmotion": "11.0.3",
- "style-value-types": "5.0.0",
- "tslib": "^2.1.0"
- },
- "optionalDependencies": {
- "@emotion/is-prop-valid": "^0.8.2"
- },
- "peerDependencies": {
- "react": ">=16.8 || ^17.0.0 || ^18.0.0",
- "react-dom": ">=16.8 || ^17.0.0 || ^18.0.0"
+ "node_modules/header-case": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz",
+ "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==",
+ "dev": true,
+ "dependencies": {
+ "capital-case": "^1.0.4",
+ "tslib": "^2.0.3"
}
},
- "node_modules/framesync": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
- "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "node_modules/hey-listen": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+ "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+ },
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"dependencies": {
- "tslib": "^2.1.0"
+ "react-is": "^16.7.0"
}
},
- "node_modules/fs-extra": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
- "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "node_modules/html-encoding-sniffer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+ "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
"dev": true,
"dependencies": {
- "at-least-node": "^1.0.0",
- "graceful-fs": "^4.2.0",
- "jsonfile": "^6.0.1",
- "universalify": "^2.0.0"
+ "whatwg-encoding": "^3.1.1"
},
"engines": {
- "node": ">=10"
+ "node": ">=18"
}
},
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "node_modules/html-url-attributes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz",
+ "integrity": "sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==",
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/function.prototype.name": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
- "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dev": true,
"dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "functions-have-names": "^1.2.3"
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">= 14"
}
},
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "node_modules/http-signature": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz",
+ "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==",
"dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^2.0.2",
+ "sshpk": "^1.18.0"
+ },
+ "engines": {
+ "node": ">=0.10"
}
},
- "node_modules/gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
+ "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
+ "dev": true,
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
"engines": {
- "node": ">=6.9.0"
+ "node": ">= 14"
}
},
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "node_modules/human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
"dev": true,
"engines": {
- "node": "6.* || 8.* || >= 10.*"
+ "node": ">=8.12.0"
}
},
- "node_modules/get-east-asian-width": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz",
- "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==",
+ "node_modules/husky": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
+ "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
"dev": true,
- "license": "MIT",
+ "bin": {
+ "husky": "lib/bin.js"
+ },
"engines": {
- "node": ">=18"
+ "node": ">=14"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://github.com/sponsors/typicode"
}
},
- "node_modules/get-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
- "dev": true,
- "engines": {
- "node": "*"
+ "node_modules/iconify-icon": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-2.1.0.tgz",
+ "integrity": "sha512-lto4XU3bwTQnb+D/CsJ4dWAo0aDe+uPMxEtxyOodw9l7R9QnJUUab3GCehlw2M8mDHdeUu/ufx8PvRQiJphhXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@iconify/types": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/cyberalien"
}
},
- "node_modules/get-intrinsic": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
- "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "has-proto": "^1.0.1",
- "has-symbols": "^1.0.3",
- "hasown": "^2.0.0"
+ "safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=0.10.0"
}
},
- "node_modules/get-nonce": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
- "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "node_modules/ieee754": {
+ "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",
+ "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.3.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+ "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "dev": true,
"engines": {
- "node": ">=6"
+ "node": ">= 4"
}
},
- "node_modules/get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "node_modules/immutable": {
+ "version": "3.7.6",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
+ "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==",
"dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"dependencies": {
- "pump": "^3.0.0"
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
},
"engines": {
- "node": ">=8"
+ "node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/get-symbol-description": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
- "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.5",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4"
- },
+ "node_modules/import-fresh/node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=4"
}
},
- "node_modules/get-tsconfig": {
- "version": "4.7.3",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz",
- "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==",
- "dev": true,
- "dependencies": {
- "resolve-pkg-maps": "^1.0.0"
- },
+ "node_modules/import-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz",
+ "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.2"
+ },
"funding": {
- "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/getos": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
- "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==",
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true,
- "dependencies": {
- "async": "^3.2.0"
+ "engines": {
+ "node": ">=8"
}
},
- "node_modules/getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "node_modules/index-to-position": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-0.1.2.tgz",
+ "integrity": "sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"dependencies": {
- "assert-plus": "^1.0.0"
+ "once": "^1.3.0",
+ "wrappy": "1"
}
},
- "node_modules/gitdiff-parser": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/gitdiff-parser/-/gitdiff-parser-0.3.1.tgz",
- "integrity": "sha512-YQJnY8aew65id8okGxKCksH3efDCJ9HzV7M9rsvd65habf39Pkh4cgYJ27AaoDMqo1X98pgNJhNMrm/kpV7UVQ=="
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
},
- "node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "node_modules/ini": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/inline-style-parser": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.2.tgz",
+ "integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ=="
+ },
+ "node_modules/inquirer": {
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
+ "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
"dev": true,
"dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.1.1",
+ "cli-cursor": "^3.1.0",
+ "cli-width": "^3.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^3.0.0",
+ "lodash": "^4.17.21",
+ "mute-stream": "0.0.8",
+ "ora": "^5.4.1",
+ "run-async": "^2.4.0",
+ "rxjs": "^7.5.5",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "through": "^2.3.6",
+ "wrap-ansi": "^6.0.1"
},
"engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "node": ">=12.0.0"
}
},
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "node_modules/internal-slot": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
+ "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
+ "dev": true,
"dependencies": {
- "is-glob": "^4.0.1"
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.0",
+ "side-channel": "^1.0.4"
},
"engines": {
- "node": ">= 6"
+ "node": ">= 0.4"
}
},
- "node_modules/global-dirs": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz",
- "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==",
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "node_modules/is-absolute": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
"dev": true,
"dependencies": {
- "ini": "2.0.0"
+ "is-relative": "^1.0.0",
+ "is-windows": "^1.0.1"
},
"engines": {
- "node": ">=10"
- },
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-alphabetical": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
+ "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "engines": {
- "node": ">=4"
+ "node_modules/is-alphanumerical": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
+ "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
+ "dependencies": {
+ "is-alphabetical": "^2.0.0",
+ "is-decimal": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/globalthis": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
- "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+ "node_modules/is-arguments": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+ "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "define-properties": "^1.1.3"
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
@@ -11227,287 +10627,219 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "node_modules/is-array-buffer": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
+ "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
"dev": true,
"dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.2.1"
},
"engines": {
- "node": ">=10"
+ "node": ">= 0.4"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/globrex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
- "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
},
- "node_modules/gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "node_modules/is-bigint": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+ "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
"dev": true,
"dependencies": {
- "get-intrinsic": "^1.1.3"
+ "has-bigints": "^1.0.1"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "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/graphiql": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/graphiql/-/graphiql-3.1.2.tgz",
- "integrity": "sha512-k3p2k+7ZgARdLnqMDV192VL47cTmPNn02n5ullULnBE1nv1dtJfUve+AJxaU+kU8JcbwCxSxu3qlIxuu1N3mDQ==",
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dependencies": {
- "@graphiql/react": "^0.20.4",
- "@graphiql/toolkit": "^0.9.1",
- "graphql-language-service": "^5.2.0",
- "markdown-it": "^12.2.0"
+ "binary-extensions": "^2.0.0"
},
- "peerDependencies": {
- "graphql": "^15.5.0 || ^16.0.0",
- "react": "^16.8.0 || ^17 || ^18",
- "react-dom": "^16.8.0 || ^17 || ^18"
- }
- },
- "node_modules/graphql": {
- "version": "16.8.1",
- "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
- "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
"engines": {
- "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
+ "node": ">=8"
}
},
- "node_modules/graphql-config": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-5.0.3.tgz",
- "integrity": "sha512-BNGZaoxIBkv9yy6Y7omvsaBUHOzfFcII3UN++tpH8MGOKFPFkCPZuwx09ggANMt8FgyWP1Od8SWPmrUEZca4NQ==",
+ "node_modules/is-boolean-object": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+ "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
"dev": true,
"dependencies": {
- "@graphql-tools/graphql-file-loader": "^8.0.0",
- "@graphql-tools/json-file-loader": "^8.0.0",
- "@graphql-tools/load": "^8.0.0",
- "@graphql-tools/merge": "^9.0.0",
- "@graphql-tools/url-loader": "^8.0.0",
- "@graphql-tools/utils": "^10.0.0",
- "cosmiconfig": "^8.1.0",
- "jiti": "^1.18.2",
- "minimatch": "^4.2.3",
- "string-env-interpolation": "^1.0.1",
- "tslib": "^2.4.0"
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
},
"engines": {
- "node": ">= 16.0.0"
- },
- "peerDependencies": {
- "cosmiconfig-toml-loader": "^1.0.0",
- "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
+ "node": ">= 0.4"
},
- "peerDependenciesMeta": {
- "cosmiconfig-toml-loader": {
- "optional": true
- }
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graphql-config/node_modules/minimatch": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.3.tgz",
- "integrity": "sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng==",
+ "node_modules/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==",
"dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
"engines": {
- "node": ">=10"
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graphql-language-service": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-5.2.0.tgz",
- "integrity": "sha512-o/ZgTS0pBxWm3hSF4+6GwiV1//DxzoLWEbS38+jqpzzy1d/QXBidwQuVYTOksclbtOJZ3KR/tZ8fi/tI6VpVMg==",
+ "node_modules/is-ci": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
+ "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
+ "dev": true,
"dependencies": {
- "nullthrows": "^1.0.0",
- "vscode-languageserver-types": "^3.17.1"
+ "ci-info": "^3.2.0"
},
"bin": {
- "graphql": "dist/temp-bin.js"
- },
- "peerDependencies": {
- "graphql": "^15.5.0 || ^16.0.0"
+ "is-ci": "bin.js"
}
},
- "node_modules/graphql-request": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz",
- "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==",
- "dev": true,
+ "node_modules/is-core-module": {
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+ "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
"dependencies": {
- "@graphql-typed-document-node/core": "^3.2.0",
- "cross-fetch": "^3.1.5"
+ "hasown": "^2.0.0"
},
- "peerDependencies": {
- "graphql": "14 - 16"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graphql-request/node_modules/cross-fetch": {
- "version": "3.1.8",
- "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
- "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
+ "node_modules/is-date-object": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+ "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
"dependencies": {
- "node-fetch": "^2.6.12"
- }
- },
- "node_modules/graphql-tag": {
- "version": "2.12.6",
- "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz",
- "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==",
- "dependencies": {
- "tslib": "^2.1.0"
+ "has-tostringtag": "^1.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">= 0.4"
},
- "peerDependencies": {
- "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graphql-ws": {
- "version": "5.16.0",
- "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz",
- "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==",
- "devOptional": true,
+ "node_modules/is-decimal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
+ "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "graphql": ">=0.11 <=16"
+ "node": ">=0.10.0"
}
},
- "node_modules/handlebars": {
- "version": "4.7.8",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
- "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
- "dependencies": {
- "minimist": "^1.2.5",
- "neo-async": "^2.6.2",
- "source-map": "^0.6.1",
- "wordwrap": "^1.0.0"
- },
- "bin": {
- "handlebars": "bin/handlebars"
- },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"engines": {
- "node": ">=0.4.7"
- },
- "optionalDependencies": {
- "uglify-js": "^3.1.4"
+ "node": ">=8"
}
},
- "node_modules/has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
- "dev": true,
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dependencies": {
- "ansi-regex": "^2.0.0"
+ "is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
- "node_modules/has-ansi/node_modules/ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
+ "node_modules/is-hexadecimal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
+ "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+ "node_modules/is-installed-globally": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
+ "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
"dev": true,
+ "dependencies": {
+ "global-dirs": "^3.0.0",
+ "is-path-inside": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "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/is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
"dev": true,
"engines": {
"node": ">=8"
}
},
- "node_modules/has-property-descriptors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
- "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "node_modules/is-lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz",
+ "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==",
"dev": true,
"dependencies": {
- "es-define-property": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "tslib": "^2.0.3"
}
},
- "node_modules/has-proto": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
- "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "node_modules/is-map": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
+ "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
"dev": true,
- "engines": {
- "node": ">= 0.4"
- },
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "dev": true,
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=0.12.0"
}
},
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "node_modules/is-number-object": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+ "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
"dev": true,
"dependencies": {
- "has-symbols": "^1.0.3"
+ "has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
@@ -11516,499 +10848,466 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
+ "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": ">= 0.4"
+ "node": ">=8"
}
},
- "node_modules/hast-util-to-jsx-runtime": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz",
- "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==",
- "dependencies": {
- "@types/estree": "^1.0.0",
- "@types/hast": "^3.0.0",
- "@types/unist": "^3.0.0",
- "comma-separated-tokens": "^2.0.0",
- "devlop": "^1.0.0",
- "estree-util-is-identifier-name": "^3.0.0",
- "hast-util-whitespace": "^3.0.0",
- "mdast-util-mdx-expression": "^2.0.0",
- "mdast-util-mdx-jsx": "^3.0.0",
- "mdast-util-mdxjs-esm": "^2.0.0",
- "property-information": "^6.0.0",
- "space-separated-tokens": "^2.0.0",
- "style-to-object": "^1.0.0",
- "unist-util-position": "^5.0.0",
- "vfile-message": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/hast-util-whitespace": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
- "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
- "dependencies": {
- "@types/hast": "^3.0.0"
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "engines": {
+ "node": ">=12"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/header-case": {
+ "node_modules/is-plain-object": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz",
- "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==",
- "dev": true,
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
"dependencies": {
- "capital-case": "^1.0.4",
- "tslib": "^2.0.3"
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
}
},
- "node_modules/hey-listen": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
- "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+ "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/hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dependencies": {
- "react-is": "^16.7.0"
+ "node_modules/is-primitive": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz",
+ "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==",
+ "engines": {
+ "node": ">=0.10.0"
}
},
- "node_modules/html-encoding-sniffer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
- "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
+ "node_modules/is-regex": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+ "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
"dependencies": {
- "whatwg-encoding": "^3.1.1"
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
},
"engines": {
- "node": ">=18"
- }
- },
- "node_modules/html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
- "dev": true
- },
- "node_modules/html-url-attributes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz",
- "integrity": "sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==",
+ "node": ">= 0.4"
+ },
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/http-proxy-agent": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
- "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "node_modules/is-relative": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
"dev": true,
"dependencies": {
- "agent-base": "^7.1.0",
- "debug": "^4.3.4"
+ "is-unc-path": "^1.0.0"
},
"engines": {
- "node": ">= 14"
+ "node": ">=0.10.0"
}
},
- "node_modules/http-signature": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz",
- "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==",
+ "node_modules/is-set": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
+ "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
"dev": true,
- "dependencies": {
- "assert-plus": "^1.0.0",
- "jsprim": "^2.0.2",
- "sshpk": "^1.14.1"
- },
- "engines": {
- "node": ">=0.10"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/https-proxy-agent": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
- "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
"dev": true,
"dependencies": {
- "agent-base": "^7.0.2",
- "debug": "4"
+ "call-bind": "^1.0.7"
},
"engines": {
- "node": ">= 14"
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/human-signals": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
- "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true,
"engines": {
- "node": ">=8.12.0"
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/husky": {
- "version": "8.0.3",
- "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
- "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
+ "node_modules/is-string": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+ "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
"dev": true,
- "bin": {
- "husky": "lib/bin.js"
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
},
"engines": {
- "node": ">=14"
+ "node": ">= 0.4"
},
"funding": {
- "url": "https://github.com/sponsors/typicode"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/iconify-icon": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-2.0.0.tgz",
- "integrity": "sha512-38ArOkxmyD9oDbJBkxaFpE6eZ0K3F9Sk+3x4mWGfjMJaxi3EKrix9Du4iWhgBFT3imKC4FJJE34ur2Rc7Xm+Uw==",
+ "node_modules/is-symbol": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+ "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "dev": true,
"dependencies": {
- "@iconify/types": "^2.0.0"
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
- "url": "https://github.com/sponsors/cyberalien"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-unc-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
"dev": true,
"dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
+ "unc-path-regex": "^0.1.2"
},
"engines": {
"node": ">=0.10.0"
}
},
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
- "node_modules/ignore": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
- "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "node_modules/is-upper-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz",
+ "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==",
"dev": true,
- "engines": {
- "node": ">= 4"
+ "dependencies": {
+ "tslib": "^2.0.3"
}
},
- "node_modules/immutable": {
- "version": "3.7.6",
- "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
- "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==",
+ "node_modules/is-weakmap": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
+ "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
"dev": true,
- "engines": {
- "node": ">=0.8.0"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "node_modules/is-weakset": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
+ "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
+ "dev": true,
"dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.1.1"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/import-fresh/node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "engines": {
- "node": ">=4"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/import-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz",
- "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==",
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
"dev": true,
"engines": {
- "node": ">=12.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=0.10.0"
}
},
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+ },
+ "node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
"engines": {
- "node": ">=0.8.19"
+ "node": ">=0.10.0"
}
},
- "node_modules/indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "node_modules/isomorphic-ws": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
+ "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
"dev": true,
- "engines": {
- "node": ">=8"
+ "peerDependencies": {
+ "ws": "*"
}
},
- "node_modules/index-to-position": {
+ "node_modules/isstream": {
"version": "0.1.2",
- "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-0.1.2.tgz",
- "integrity": "sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
"dev": true,
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
+ "license": "MIT"
},
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "node_modules/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,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
+ "engines": {
+ "node": ">=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==",
- "dev": true
- },
- "node_modules/ini": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
- "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+ "node_modules/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,
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^4.0.0",
+ "supports-color": "^7.1.0"
+ },
"engines": {
"node": ">=10"
}
},
- "node_modules/inline-style-parser": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.2.tgz",
- "integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ=="
- },
- "node_modules/inquirer": {
- "version": "8.2.6",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
- "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.4.tgz",
+ "integrity": "sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==",
"dev": true,
"dependencies": {
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.1.1",
- "cli-cursor": "^3.1.0",
- "cli-width": "^3.0.0",
- "external-editor": "^3.0.3",
- "figures": "^3.0.0",
- "lodash": "^4.17.21",
- "mute-stream": "0.0.8",
- "ora": "^5.4.1",
- "run-async": "^2.4.0",
- "rxjs": "^7.5.5",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0",
- "through": "^2.3.6",
- "wrap-ansi": "^6.0.1"
+ "@jridgewell/trace-mapping": "^0.3.23",
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=10"
}
},
- "node_modules/internal-slot": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
- "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
+ "node_modules/istanbul-reports": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
+ "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
"dev": true,
"dependencies": {
- "es-errors": "^1.3.0",
- "hasown": "^2.0.0",
- "side-channel": "^1.0.4"
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
},
"engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/internmap": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
- "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
- "engines": {
- "node": ">=12"
+ "node": ">=8"
}
},
- "node_modules/invariant": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "dependencies": {
- "loose-envify": "^1.0.0"
- }
+ "node_modules/iterall": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
+ "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg=="
},
- "node_modules/is-absolute": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
- "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
- "dev": true,
+ "node_modules/jackspeak": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
+ "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"dependencies": {
- "is-relative": "^1.0.0",
- "is-windows": "^1.0.1"
+ "@isaacs/cliui": "^8.0.2"
},
"engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-alphabetical": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
- "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
+ "node": ">=14"
+ },
"funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
}
},
- "node_modules/is-alphanumerical": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
- "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
- "dependencies": {
- "is-alphabetical": "^2.0.0",
- "is-decimal": "^2.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "node_modules/jiti": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
+ "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
+ "bin": {
+ "jiti": "bin/jiti.js"
}
},
- "node_modules/is-arguments": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
- "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+ "node_modules/jose": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.3.tgz",
+ "integrity": "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==",
"dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/panva"
}
},
- "node_modules/is-array-buffer": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
- "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.2.1"
- },
+ "node_modules/jotai": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.10.0.tgz",
+ "integrity": "sha512-8W4u0aRlOIwGlLQ0sqfl/c6+eExl5D8lZgAUolirZLktyaj4WnxO/8a0HEPmtriQAB6X5LMhXzZVmw02X0P0qQ==",
+ "license": "MIT",
"engines": {
- "node": ">= 0.4"
+ "node": ">=12.20.0"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "peerDependencies": {
+ "@types/react": ">=17.0.0",
+ "react": ">=17.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
}
},
- "node_modules/is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
- },
- "node_modules/is-async-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
- "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
+ "node_modules/js-levenshtein": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
+ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
"dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
"engines": {
- "node": ">= 0.4"
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dependencies": {
+ "argparse": "^2.0.1"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsdom": {
+ "version": "24.0.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz",
+ "integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==",
"dev": true,
"dependencies": {
- "has-bigints": "^1.0.1"
+ "cssstyle": "^4.0.1",
+ "data-urls": "^5.0.0",
+ "decimal.js": "^10.4.3",
+ "form-data": "^4.0.0",
+ "html-encoding-sniffer": "^4.0.0",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.2",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.7",
+ "parse5": "^7.1.2",
+ "rrweb-cssom": "^0.6.0",
+ "saxes": "^6.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^4.1.3",
+ "w3c-xmlserializer": "^5.0.0",
+ "webidl-conversions": "^7.0.0",
+ "whatwg-encoding": "^3.1.1",
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0",
+ "ws": "^8.16.0",
+ "xml-name-validator": "^5.0.0"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "canvas": "^2.11.2"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
}
},
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dependencies": {
- "binary-extensions": "^2.0.0"
+ "node_modules/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "bin": {
+ "jsesc": "bin/jsesc"
},
"engines": {
- "node": ">=8"
+ "node": ">=4"
}
},
- "node_modules/is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
+ },
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+ "dev": true,
+ "license": "(AFL-2.1 OR BSD-3-Clause)"
+ },
+ "node_modules/json-stable-stringify": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz",
+ "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==",
"dev": true,
"dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
+ "call-bind": "^1.0.5",
+ "isarray": "^2.0.5",
+ "jsonify": "^0.0.1",
+ "object-keys": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
@@ -12017,2290 +11316,1392 @@
"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==",
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/json-to-graphql-query": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/json-to-graphql-query/-/json-to-graphql-query-2.2.5.tgz",
+ "integrity": "sha512-5Nom9inkIMrtY992LMBBG1Zaekrc10JaRhyZgprwHBVMDtRgllTvzl0oBbg13wJsVZoSoFNNMaeIVQs0P04vsA==",
+ "license": "MIT"
+ },
+ "node_modules/json-to-pretty-yaml": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz",
+ "integrity": "sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A==",
"dev": true,
"dependencies": {
- "builtin-modules": "^3.3.0"
+ "remedial": "^1.0.7",
+ "remove-trailing-spaces": "^1.0.6"
},
"engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">= 0.2.0"
}
},
- "node_modules/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==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "bin": {
+ "json5": "lib/cli.js"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "engines": {
+ "node": ">=6"
}
},
- "node_modules/is-ci": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
- "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"dependencies": {
- "ci-info": "^3.2.0"
+ "universalify": "^2.0.0"
},
- "bin": {
- "is-ci": "bin.js"
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
}
},
- "node_modules/is-core-module": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
- "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
- "dependencies": {
- "hasown": "^2.0.0"
- },
+ "node_modules/jsonify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz",
+ "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
+ "dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-data-view": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
- "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
+ "node_modules/jsprim": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
+ "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==",
"dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT",
"dependencies": {
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.4.0",
+ "verror": "1.10.0"
}
},
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "node_modules/lazy-ass": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
+ "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
"dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-decimal": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
- "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "node": "> 0.8"
}
},
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=10"
}
},
- "node_modules/is-finalizationregistry": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
- "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "engines": {
- "node": ">=8"
+ "node_modules/linkify-it": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+ "dependencies": {
+ "uc.micro": "^1.0.1"
}
},
- "node_modules/is-generator-function": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
- "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+ "node_modules/lint-staged": {
+ "version": "15.2.10",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz",
+ "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "has-tostringtag": "^1.0.0"
+ "chalk": "~5.3.0",
+ "commander": "~12.1.0",
+ "debug": "~4.3.6",
+ "execa": "~8.0.1",
+ "lilconfig": "~3.1.2",
+ "listr2": "~8.2.4",
+ "micromatch": "~4.0.8",
+ "pidtree": "~0.6.0",
+ "string-argv": "~0.3.2",
+ "yaml": "~2.5.0"
+ },
+ "bin": {
+ "lint-staged": "bin/lint-staged.js"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=18.12.0"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://opencollective.com/lint-staged"
}
},
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "node_modules/lint-staged/node_modules/ansi-escapes": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
+ "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "is-extglob": "^2.1.1"
+ "environment": "^1.0.0"
},
"engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-hexadecimal": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
- "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
+ "node": ">=18"
+ },
"funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-installed-globally": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
- "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
+ "node_modules/lint-staged/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
"dev": true,
- "dependencies": {
- "global-dirs": "^3.0.0",
- "is-path-inside": "^3.0.2"
- },
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=12"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
- "node_modules/is-interactive": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
- "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "node_modules/lint-staged/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/is-lower-case": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz",
- "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==",
+ "node_modules/lint-staged/node_modules/chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
"dev": true,
- "dependencies": {
- "tslib": "^2.0.3"
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/is-map": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
- "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
+ "node_modules/lint-staged/node_modules/cli-cursor": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
+ "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-negative-zero": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
- "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "node_modules/lint-staged/node_modules/cli-truncate": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
+ "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "slice-ansi": "^5.0.0",
+ "string-width": "^7.0.0"
+ },
"engines": {
- "node": ">= 0.4"
+ "node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "node_modules/lint-staged/node_modules/commander": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
+ "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
+ "dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=0.12.0"
+ "node": ">=18"
}
},
- "node_modules/is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "node_modules/lint-staged/node_modules/emoji-regex": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lint-staged/node_modules/execa": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
+ "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "has-tostringtag": "^1.0.0"
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^8.0.1",
+ "human-signals": "^5.0.0",
+ "is-stream": "^3.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^5.1.0",
+ "onetime": "^6.0.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^3.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=16.17"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
- "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==",
+ "node_modules/lint-staged/node_modules/get-stream": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-plain-obj": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
- "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
- "engines": {
- "node": ">=12"
+ "node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dependencies": {
- "isobject": "^3.0.1"
- },
+ "node_modules/lint-staged/node_modules/human-signals": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
+ "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
+ "dev": true,
+ "license": "Apache-2.0",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=16.17.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-primitive": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz",
- "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==",
+ "node_modules/lint-staged/node_modules/is-fullwidth-code-point": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
+ "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
+ "dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "node_modules/lint-staged/node_modules/is-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
+ "license": "MIT",
"engines": {
- "node": ">= 0.4"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-relative": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
- "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+ "node_modules/lint-staged/node_modules/lilconfig": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
+ "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
"dev": true,
- "dependencies": {
- "is-unc-path": "^1.0.0"
- },
+ "license": "MIT",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
}
},
- "node_modules/is-set": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
- "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
+ "node_modules/lint-staged/node_modules/listr2": {
+ "version": "8.2.4",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz",
+ "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==",
"dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "license": "MIT",
+ "dependencies": {
+ "cli-truncate": "^4.0.0",
+ "colorette": "^2.0.20",
+ "eventemitter3": "^5.0.1",
+ "log-update": "^6.1.0",
+ "rfdc": "^1.4.1",
+ "wrap-ansi": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
}
},
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
- "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
+ "node_modules/lint-staged/node_modules/log-update": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
+ "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7"
+ "ansi-escapes": "^7.0.0",
+ "cli-cursor": "^5.0.0",
+ "slice-ansi": "^7.1.0",
+ "strip-ansi": "^7.1.0",
+ "wrap-ansi": "^9.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "node_modules/lint-staged/node_modules/log-update/node_modules/is-fullwidth-code-point": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
+ "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-east-asian-width": "^1.0.0"
+ },
"engines": {
- "node": ">=8"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "node_modules/lint-staged/node_modules/log-update/node_modules/slice-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
+ "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "has-tostringtag": "^1.0.0"
+ "ansi-styles": "^6.2.1",
+ "is-fullwidth-code-point": "^5.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
- "node_modules/is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "node_modules/lint-staged/node_modules/mimic-fn": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lint-staged/node_modules/npm-run-path": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
+ "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "has-symbols": "^1.0.2"
+ "path-key": "^4.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-typed-array": {
- "version": "1.1.13",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
- "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+ "node_modules/lint-staged/node_modules/onetime": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "which-typed-array": "^1.1.14"
+ "mimic-fn": "^4.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=12"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
- "dev": true
+ "node_modules/lint-staged/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
- "node_modules/is-unc-path": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
- "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+ "node_modules/lint-staged/node_modules/restore-cursor": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
+ "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "unc-path-regex": "^0.1.2"
+ "onetime": "^7.0.0",
+ "signal-exit": "^4.1.0"
},
"engines": {
- "node": ">=0.10.0"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-unicode-supported": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
- "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "node_modules/lint-staged/node_modules/restore-cursor/node_modules/onetime": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
+ "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-function": "^5.0.0"
+ },
"engines": {
- "node": ">=10"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-upper-case": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz",
- "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==",
+ "node_modules/lint-staged/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,
- "dependencies": {
- "tslib": "^2.0.3"
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/is-weakmap": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
- "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
+ "node_modules/lint-staged/node_modules/slice-ansi": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
+ "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.0.0",
+ "is-fullwidth-code-point": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
- "node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+ "node_modules/lint-staged/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.2"
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-weakset": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
- "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
+ "node_modules/lint-staged/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
- "node_modules/is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "node_modules/lint-staged/node_modules/strip-final-newline": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
- },
- "node_modules/isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/isomorphic-ws": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
- "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
- "dev": true,
- "peerDependencies": {
- "ws": "*"
- }
- },
- "node_modules/isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
- "dev": true
- },
- "node_modules/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==",
+ "node_modules/lint-staged/node_modules/wrap-ansi": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
+ "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.2.1",
+ "string-width": "^7.0.0",
+ "strip-ansi": "^7.1.0"
+ },
"engines": {
- "node": ">=8"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/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==",
+ "node_modules/listr2": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz",
+ "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==",
"dev": true,
"dependencies": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^4.0.0",
- "supports-color": "^7.1.0"
+ "cli-truncate": "^2.1.0",
+ "colorette": "^2.0.16",
+ "log-update": "^4.0.0",
+ "p-map": "^4.0.0",
+ "rfdc": "^1.3.0",
+ "rxjs": "^7.5.5",
+ "through": "^2.3.8",
+ "wrap-ansi": "^7.0.0"
},
"engines": {
- "node": ">=10"
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "enquirer": ">= 2.3.0 < 3"
+ },
+ "peerDependenciesMeta": {
+ "enquirer": {
+ "optional": true
+ }
}
},
- "node_modules/istanbul-lib-source-maps": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.4.tgz",
- "integrity": "sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==",
+ "node_modules/listr2/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
- "@jridgewell/trace-mapping": "^0.3.23",
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0"
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/istanbul-reports": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
- "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
+ "node_modules/local-pkg": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
+ "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
+ "mlly": "^1.4.2",
+ "pkg-types": "^1.0.3"
},
"engines": {
- "node": ">=8"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
}
},
- "node_modules/iterall": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
- "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg=="
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
- "node_modules/iterator.prototype": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
- "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==",
- "dev": true,
- "dependencies": {
- "define-properties": "^1.2.1",
- "get-intrinsic": "^1.2.1",
- "has-symbols": "^1.0.3",
- "reflect.getprototypeof": "^1.0.4",
- "set-function-name": "^2.0.1"
- }
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
- "node_modules/jackspeak": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
- "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
+ "dev": true
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "dev": true
+ },
+ "node_modules/lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
+ "dev": true
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
"dependencies": {
- "@isaacs/cliui": "^8.0.2"
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
},
"engines": {
- "node": ">=14"
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
- },
- "optionalDependencies": {
- "@pkgjs/parseargs": "^0.11.0"
- }
- },
- "node_modules/jiti": {
- "version": "1.21.0",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
- "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
- "bin": {
- "jiti": "bin/jiti.js"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/jose": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.3.tgz",
- "integrity": "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==",
+ "node_modules/log-update": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+ "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
"dev": true,
- "funding": {
- "url": "https://github.com/sponsors/panva"
- }
- },
- "node_modules/jotai": {
- "version": "2.7.2",
- "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.7.2.tgz",
- "integrity": "sha512-6Ft5kpNu8p93Ssf1Faoza3hYQZRIYp7rioK8MwTTFnbQKwUyZElwquPwl1h6U0uo9hC0jr+ghO3gcSjc6P35/Q==",
- "engines": {
- "node": ">=12.20.0"
+ "dependencies": {
+ "ansi-escapes": "^4.3.0",
+ "cli-cursor": "^3.1.0",
+ "slice-ansi": "^4.0.0",
+ "wrap-ansi": "^6.2.0"
},
- "peerDependencies": {
- "@types/react": ">=17.0.0",
- "react": ">=17.0.0"
+ "engines": {
+ "node": ">=10"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "react": {
- "optional": true
- }
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/js-levenshtein": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
- "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
+ "node_modules/log-update/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==",
"dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ "node_modules/longest-streak": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
+ "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
},
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dependencies": {
- "argparse": "^2.0.1"
+ "js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
- "js-yaml": "bin/js-yaml.js"
+ "loose-envify": "cli.js"
}
},
- "node_modules/jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
- "dev": true
- },
- "node_modules/jsdom": {
- "version": "24.0.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz",
- "integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==",
+ "node_modules/loupe": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
+ "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "cssstyle": "^4.0.1",
- "data-urls": "^5.0.0",
- "decimal.js": "^10.4.3",
- "form-data": "^4.0.0",
- "html-encoding-sniffer": "^4.0.0",
- "http-proxy-agent": "^7.0.0",
- "https-proxy-agent": "^7.0.2",
- "is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.7",
- "parse5": "^7.1.2",
- "rrweb-cssom": "^0.6.0",
- "saxes": "^6.0.0",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^4.1.3",
- "w3c-xmlserializer": "^5.0.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^3.1.1",
- "whatwg-mimetype": "^4.0.0",
- "whatwg-url": "^14.0.0",
- "ws": "^8.16.0",
- "xml-name-validator": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "canvas": "^2.11.2"
- },
- "peerDependenciesMeta": {
- "canvas": {
- "optional": true
- }
+ "get-func-name": "^2.0.1"
}
},
- "node_modules/jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=4"
+ "node_modules/lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+ "dependencies": {
+ "tslib": "^2.0.3"
}
},
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true
- },
- "node_modules/json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
- },
- "node_modules/json-schema": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
- "dev": true
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "node_modules/json-stable-stringify": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz",
- "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==",
+ "node_modules/lower-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-2.0.2.tgz",
+ "integrity": "sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==",
"dev": true,
"dependencies": {
- "call-bind": "^1.0.5",
- "isarray": "^2.0.5",
- "jsonify": "^0.0.1",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "tslib": "^2.0.3"
}
},
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "node_modules/json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
- "dev": true
- },
- "node_modules/json-to-graphql-query": {
- "version": "2.2.5",
- "resolved": "https://registry.npmjs.org/json-to-graphql-query/-/json-to-graphql-query-2.2.5.tgz",
- "integrity": "sha512-5Nom9inkIMrtY992LMBBG1Zaekrc10JaRhyZgprwHBVMDtRgllTvzl0oBbg13wJsVZoSoFNNMaeIVQs0P04vsA==",
- "license": "MIT"
- },
- "node_modules/json-to-pretty-yaml": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz",
- "integrity": "sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A==",
- "dev": true,
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dependencies": {
- "remedial": "^1.0.7",
- "remove-trailing-spaces": "^1.0.6"
- },
- "engines": {
- "node": ">= 0.2.0"
+ "yallist": "^3.0.2"
}
},
- "node_modules/json5": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
- "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "node_modules/lz-string": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+ "dev": true,
+ "license": "MIT",
"bin": {
- "json5": "lib/cli.js"
- },
- "engines": {
- "node": ">=6"
+ "lz-string": "bin/bin.js"
}
},
- "node_modules/jsonc-parser": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
- "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==",
- "dev": true
- },
- "node_modules/jsonfile": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
- "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "node_modules/magic-string": {
+ "version": "0.30.11",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
+ "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "universalify": "^2.0.0"
- },
- "optionalDependencies": {
- "graceful-fs": "^4.1.6"
+ "@jridgewell/sourcemap-codec": "^1.5.0"
}
},
- "node_modules/jsonify": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz",
- "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
+ "node_modules/magicast": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.3.tgz",
+ "integrity": "sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==",
"dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "dependencies": {
+ "@babel/parser": "^7.23.6",
+ "@babel/types": "^7.23.6",
+ "source-map-js": "^1.0.2"
}
},
- "node_modules/jsprim": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
- "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==",
+ "node_modules/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,
- "engines": [
- "node >=0.6.0"
- ],
"dependencies": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.4.0",
- "verror": "1.10.0"
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/jsx-ast-utils": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
- "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+ "node_modules/make-dir/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
- "array-includes": "^3.1.6",
- "array.prototype.flat": "^1.3.1",
- "object.assign": "^4.1.4",
- "object.values": "^1.1.6"
+ "yallist": "^4.0.0"
},
"engines": {
- "node": ">=4.0"
+ "node": ">=10"
}
},
- "node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "node_modules/make-dir/node_modules/semver": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+ "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true,
"dependencies": {
- "json-buffer": "3.0.1"
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
}
},
- "node_modules/lazy-ass": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
- "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
+ "node_modules/make-dir/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "optional": true,
+ "peer": true
+ },
+ "node_modules/map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
"dev": true,
"engines": {
- "node": "> 0.8"
+ "node": ">=0.10.0"
}
},
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
+ "node_modules/markdown-it": {
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
"dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
+ "argparse": "^2.0.1",
+ "entities": "~2.1.0",
+ "linkify-it": "^3.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
},
- "engines": {
- "node": ">= 0.8.0"
+ "bin": {
+ "markdown-it": "bin/markdown-it.js"
}
},
- "node_modules/lilconfig": {
+ "node_modules/markdown-it/node_modules/entities": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
- "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/lines-and-columns": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
- "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
},
- "node_modules/linkify-it": {
+ "node_modules/markdown-table": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
- "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
- "dependencies": {
- "uc.micro": "^1.0.1"
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
+ "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/lint-staged": {
- "version": "15.2.10",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.10.tgz",
- "integrity": "sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-find-and-replace": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz",
+ "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==",
"dependencies": {
- "chalk": "~5.3.0",
- "commander": "~12.1.0",
- "debug": "~4.3.6",
- "execa": "~8.0.1",
- "lilconfig": "~3.1.2",
- "listr2": "~8.2.4",
- "micromatch": "~4.0.8",
- "pidtree": "~0.6.0",
- "string-argv": "~0.3.2",
- "yaml": "~2.5.0"
- },
- "bin": {
- "lint-staged": "bin/lint-staged.js"
- },
- "engines": {
- "node": ">=18.12.0"
+ "@types/mdast": "^4.0.0",
+ "escape-string-regexp": "^5.0.0",
+ "unist-util-is": "^6.0.0",
+ "unist-util-visit-parents": "^6.0.0"
},
"funding": {
- "url": "https://opencollective.com/lint-staged"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/ansi-escapes": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz",
- "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "environment": "^1.0.0"
- },
+ "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"engines": {
- "node": ">=18"
+ "node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/lint-staged/node_modules/ansi-regex": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
+ "node_modules/mdast-util-from-markdown": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz",
+ "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-to-string": "^4.0.0",
+ "micromark": "^4.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-decode-string": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unist-util-stringify-position": "^4.0.0"
},
"funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/ansi-styles": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
- "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
+ "node_modules/mdast-util-gfm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz",
+ "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==",
+ "dependencies": {
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-gfm-autolink-literal": "^2.0.0",
+ "mdast-util-gfm-footnote": "^2.0.0",
+ "mdast-util-gfm-strikethrough": "^2.0.0",
+ "mdast-util-gfm-table": "^2.0.0",
+ "mdast-util-gfm-task-list-item": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
},
"funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/chalk": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
- "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
- "dev": true,
- "engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ "node_modules/mdast-util-gfm-autolink-literal": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz",
+ "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-find-and-replace": "^3.0.0",
+ "micromark-util-character": "^2.0.0"
},
"funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/cli-cursor": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
- "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-gfm-footnote": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz",
+ "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==",
"dependencies": {
- "restore-cursor": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.1.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/cli-truncate": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
- "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-gfm-strikethrough": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
+ "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
"dependencies": {
- "slice-ansi": "^5.0.0",
- "string-width": "^7.0.0"
- },
- "engines": {
- "node": ">=18"
+ "@types/mdast": "^4.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lint-staged/node_modules/commander": {
- "version": "12.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
- "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/emoji-regex": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
- "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lint-staged/node_modules/execa": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
- "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-gfm-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
+ "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
"dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^8.0.1",
- "human-signals": "^5.0.0",
- "is-stream": "^3.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^5.1.0",
- "onetime": "^6.0.0",
- "signal-exit": "^4.1.0",
- "strip-final-newline": "^3.0.0"
- },
- "engines": {
- "node": ">=16.17"
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "markdown-table": "^3.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/get-stream": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
- "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=16"
+ "node_modules/mdast-util-gfm-task-list-item": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
+ "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/human-signals": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
- "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=16.17.0"
- }
- },
- "node_modules/lint-staged/node_modules/is-fullwidth-code-point": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
- "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
+ "node_modules/mdast-util-mdx-expression": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz",
+ "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/is-stream": {
+ "node_modules/mdast-util-mdx-jsx": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
- "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lint-staged/node_modules/lilconfig": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
- "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=14"
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz",
+ "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.1.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "parse-entities": "^4.0.0",
+ "stringify-entities": "^4.0.0",
+ "unist-util-remove-position": "^5.0.0",
+ "unist-util-stringify-position": "^4.0.0",
+ "vfile-message": "^4.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/antonk52"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/listr2": {
- "version": "8.2.4",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz",
- "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-mdxjs-esm": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz",
+ "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==",
"dependencies": {
- "cli-truncate": "^4.0.0",
- "colorette": "^2.0.20",
- "eventemitter3": "^5.0.1",
- "log-update": "^6.1.0",
- "rfdc": "^1.4.1",
- "wrap-ansi": "^9.0.0"
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
},
- "engines": {
- "node": ">=18.0.0"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/log-update": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
- "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-phrasing": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz",
+ "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==",
"dependencies": {
- "ansi-escapes": "^7.0.0",
- "cli-cursor": "^5.0.0",
- "slice-ansi": "^7.1.0",
- "strip-ansi": "^7.1.0",
- "wrap-ansi": "^9.0.0"
- },
- "engines": {
- "node": ">=18"
+ "@types/mdast": "^4.0.0",
+ "unist-util-is": "^6.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/log-update/node_modules/is-fullwidth-code-point": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz",
- "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-to-hast": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz",
+ "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==",
"dependencies": {
- "get-east-asian-width": "^1.0.0"
- },
- "engines": {
- "node": ">=18"
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "@ungap/structured-clone": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "trim-lines": "^3.0.0",
+ "unist-util-position": "^5.0.0",
+ "unist-util-visit": "^5.0.0",
+ "vfile": "^6.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/log-update/node_modules/slice-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz",
- "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==",
- "dev": true,
- "license": "MIT",
+ "node_modules/mdast-util-to-markdown": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz",
+ "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==",
"dependencies": {
- "ansi-styles": "^6.2.1",
- "is-fullwidth-code-point": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "longest-streak": "^3.0.0",
+ "mdast-util-phrasing": "^4.0.0",
+ "mdast-util-to-string": "^4.0.0",
+ "micromark-util-decode-string": "^2.0.0",
+ "unist-util-visit": "^5.0.0",
+ "zwitch": "^2.0.0"
},
"funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/mimic-fn": {
+ "node_modules/mdast-util-to-string": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
- "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lint-staged/node_modules/npm-run-path": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
- "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
- "dev": true,
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
+ "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
"dependencies": {
- "path-key": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "@types/mdast": "^4.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/onetime": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
- "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "mimic-fn": "^4.0.0"
- },
+ "node_modules/mdn-data": {
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
+ },
+ "node_modules/mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "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==",
"engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">= 8"
}
},
- "node_modules/lint-staged/node_modules/path-key": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
- "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
- "dev": true,
- "license": "MIT",
+ "node_modules/meros": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.0.tgz",
+ "integrity": "sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==",
"engines": {
- "node": ">=12"
+ "node": ">=13"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "peerDependencies": {
+ "@types/node": ">=13"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
}
},
- "node_modules/lint-staged/node_modules/restore-cursor": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
- "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
- "dev": true,
- "license": "MIT",
+ "node_modules/micromark": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz",
+ "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
"dependencies": {
- "onetime": "^7.0.0",
- "signal-exit": "^4.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "@types/debug": "^4.0.0",
+ "debug": "^4.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-encode": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-subtokenize": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
}
},
- "node_modules/lint-staged/node_modules/restore-cursor/node_modules/onetime": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
- "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
- "dev": true,
- "license": "MIT",
+ "node_modules/micromark-core-commonmark": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz",
+ "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
"dependencies": {
- "mimic-function": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-factory-destination": "^2.0.0",
+ "micromark-factory-label": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-factory-title": "^2.0.0",
+ "micromark-factory-whitespace": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-html-tag-name": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-subtokenize": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
}
},
- "node_modules/lint-staged/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,
- "license": "ISC",
- "engines": {
- "node": ">=14"
+ "node_modules/micromark-extension-gfm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
+ "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
+ "dependencies": {
+ "micromark-extension-gfm-autolink-literal": "^2.0.0",
+ "micromark-extension-gfm-footnote": "^2.0.0",
+ "micromark-extension-gfm-strikethrough": "^2.0.0",
+ "micromark-extension-gfm-table": "^2.0.0",
+ "micromark-extension-gfm-tagfilter": "^2.0.0",
+ "micromark-extension-gfm-task-list-item": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/slice-ansi": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
- "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
- "dev": true,
- "license": "MIT",
+ "node_modules/micromark-extension-gfm-autolink-literal": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz",
+ "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==",
"dependencies": {
- "ansi-styles": "^6.0.0",
- "is-fullwidth-code-point": "^4.0.0"
- },
- "engines": {
- "node": ">=12"
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
},
"funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/string-width": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
- "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
- "dev": true,
- "license": "MIT",
+ "node_modules/micromark-extension-gfm-footnote": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz",
+ "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==",
"dependencies": {
- "emoji-regex": "^10.3.0",
- "get-east-asian-width": "^1.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dev": true,
- "license": "MIT",
+ "node_modules/micromark-extension-gfm-strikethrough": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz",
+ "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==",
"dependencies": {
- "ansi-regex": "^6.0.1"
- },
- "engines": {
- "node": ">=12"
+ "devlop": "^1.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
},
"funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/strip-final-newline": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
- "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
+ "node_modules/micromark-extension-gfm-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz",
+ "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/lint-staged/node_modules/wrap-ansi": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
- "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==",
- "dev": true,
- "license": "MIT",
+ "node_modules/micromark-extension-gfm-tagfilter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
+ "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
"dependencies": {
- "ansi-styles": "^6.2.1",
- "string-width": "^7.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
+ "micromark-util-types": "^2.0.0"
},
"funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/listr2": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz",
- "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==",
- "dev": true,
+ "node_modules/micromark-extension-gfm-task-list-item": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz",
+ "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==",
"dependencies": {
- "cli-truncate": "^2.1.0",
- "colorette": "^2.0.16",
- "log-update": "^4.0.0",
- "p-map": "^4.0.0",
- "rfdc": "^1.3.0",
- "rxjs": "^7.5.5",
- "through": "^2.3.8",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "peerDependencies": {
- "enquirer": ">= 2.3.0 < 3"
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
},
- "peerDependenciesMeta": {
- "enquirer": {
- "optional": true
- }
- }
- },
- "node_modules/listr2/node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/local-pkg": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
- "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
- "dev": true,
- "dependencies": {
- "mlly": "^1.4.2",
- "pkg-types": "^1.0.3"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
- }
- },
- "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"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
- },
- "node_modules/lodash.isequal": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
- "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
- "dev": true
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "node_modules/lodash.once": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
- "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
- "dev": true
- },
- "node_modules/lodash.sortby": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
- "dev": true
- },
- "node_modules/log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/log-update": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
- "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
- "dev": true,
- "dependencies": {
- "ansi-escapes": "^4.3.0",
- "cli-cursor": "^3.1.0",
- "slice-ansi": "^4.0.0",
- "wrap-ansi": "^6.2.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/log-update/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==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
- }
- },
- "node_modules/loglevel": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz",
- "integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==",
- "dev": true,
- "engines": {
- "node": ">= 0.6.0"
- },
- "funding": {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/loglevel"
- }
- },
- "node_modules/loglevel-colored-level-prefix": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz",
- "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==",
- "dev": true,
- "dependencies": {
- "chalk": "^1.1.3",
- "loglevel": "^1.4.1"
- }
- },
- "node_modules/loglevel-colored-level-prefix/node_modules/ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/loglevel-colored-level-prefix/node_modules/ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/loglevel-colored-level-prefix/node_modules/chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/loglevel-colored-level-prefix/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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/loglevel-colored-level-prefix/node_modules/strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/loglevel-colored-level-prefix/node_modules/supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/longest-streak": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
- "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/loupe": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz",
- "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==",
- "dev": true,
- "dependencies": {
- "get-func-name": "^2.0.1"
- }
- },
- "node_modules/lower-case": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
- "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
- "dependencies": {
- "tslib": "^2.0.3"
- }
- },
- "node_modules/lower-case-first": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-2.0.2.tgz",
- "integrity": "sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==",
- "dev": true,
- "dependencies": {
- "tslib": "^2.0.3"
- }
- },
- "node_modules/lru-cache": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
- "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
- "dependencies": {
- "yallist": "^3.0.2"
- }
- },
- "node_modules/lz-string": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
- "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
- "dev": true,
- "bin": {
- "lz-string": "bin/bin.js"
- }
- },
- "node_modules/magic-string": {
- "version": "0.30.8",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
- "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/sourcemap-codec": "^1.4.15"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/magicast": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.3.tgz",
- "integrity": "sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==",
- "dev": true,
- "dependencies": {
- "@babel/parser": "^7.23.6",
- "@babel/types": "^7.23.6",
- "source-map-js": "^1.0.2"
- }
- },
- "node_modules/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,
- "dependencies": {
- "semver": "^7.5.3"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/make-dir/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/make-dir/node_modules/semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/make-dir/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "devOptional": true
- },
- "node_modules/map-cache": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
- "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/markdown-it": {
- "version": "12.3.2",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
- "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
- "dependencies": {
- "argparse": "^2.0.1",
- "entities": "~2.1.0",
- "linkify-it": "^3.0.1",
- "mdurl": "^1.0.1",
- "uc.micro": "^1.0.5"
- },
- "bin": {
- "markdown-it": "bin/markdown-it.js"
- }
- },
- "node_modules/markdown-it/node_modules/entities": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
- "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/markdown-table": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
- "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/mdast-util-find-and-replace": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz",
- "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "escape-string-regexp": "^5.0.0",
- "unist-util-is": "^6.0.0",
- "unist-util-visit-parents": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
- "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mdast-util-from-markdown": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz",
- "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "@types/unist": "^3.0.0",
- "decode-named-character-reference": "^1.0.0",
- "devlop": "^1.0.0",
- "mdast-util-to-string": "^4.0.0",
- "micromark": "^4.0.0",
- "micromark-util-decode-numeric-character-reference": "^2.0.0",
- "micromark-util-decode-string": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0",
- "unist-util-stringify-position": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-gfm": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz",
- "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==",
- "dependencies": {
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-gfm-autolink-literal": "^2.0.0",
- "mdast-util-gfm-footnote": "^2.0.0",
- "mdast-util-gfm-strikethrough": "^2.0.0",
- "mdast-util-gfm-table": "^2.0.0",
- "mdast-util-gfm-task-list-item": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-gfm-autolink-literal": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz",
- "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "ccount": "^2.0.0",
- "devlop": "^1.0.0",
- "mdast-util-find-and-replace": "^3.0.0",
- "micromark-util-character": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-gfm-footnote": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz",
- "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "devlop": "^1.1.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-gfm-strikethrough": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
- "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-gfm-table": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
- "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "devlop": "^1.0.0",
- "markdown-table": "^3.0.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-gfm-task-list-item": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
- "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "devlop": "^1.0.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-mdx-expression": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz",
- "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==",
- "dependencies": {
- "@types/estree-jsx": "^1.0.0",
- "@types/hast": "^3.0.0",
- "@types/mdast": "^4.0.0",
- "devlop": "^1.0.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-mdx-jsx": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz",
- "integrity": "sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==",
- "dependencies": {
- "@types/estree-jsx": "^1.0.0",
- "@types/hast": "^3.0.0",
- "@types/mdast": "^4.0.0",
- "@types/unist": "^3.0.0",
- "ccount": "^2.0.0",
- "devlop": "^1.1.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0",
- "parse-entities": "^4.0.0",
- "stringify-entities": "^4.0.0",
- "unist-util-remove-position": "^5.0.0",
- "unist-util-stringify-position": "^4.0.0",
- "vfile-message": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-mdxjs-esm": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz",
- "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==",
- "dependencies": {
- "@types/estree-jsx": "^1.0.0",
- "@types/hast": "^3.0.0",
- "@types/mdast": "^4.0.0",
- "devlop": "^1.0.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-phrasing": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz",
- "integrity": "sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "unist-util-is": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-to-hast": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz",
- "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==",
- "dependencies": {
- "@types/hast": "^3.0.0",
- "@types/mdast": "^4.0.0",
- "@ungap/structured-clone": "^1.0.0",
- "devlop": "^1.0.0",
- "micromark-util-sanitize-uri": "^2.0.0",
- "trim-lines": "^3.0.0",
- "unist-util-position": "^5.0.0",
- "unist-util-visit": "^5.0.0",
- "vfile": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-to-markdown": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz",
- "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "@types/unist": "^3.0.0",
- "longest-streak": "^3.0.0",
- "mdast-util-phrasing": "^4.0.0",
- "mdast-util-to-string": "^4.0.0",
- "micromark-util-decode-string": "^2.0.0",
- "unist-util-visit": "^5.0.0",
- "zwitch": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-to-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
- "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
- "dependencies": {
- "@types/mdast": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdn-data": {
- "version": "2.0.30",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
- "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
- },
- "node_modules/mdurl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
- "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
- },
- "node_modules/merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "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==",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/meros": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.0.tgz",
- "integrity": "sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==",
- "engines": {
- "node": ">=13"
- },
- "peerDependencies": {
- "@types/node": ">=13"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
- }
- },
- "node_modules/micromark": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz",
- "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==",
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "dependencies": {
- "@types/debug": "^4.0.0",
- "debug": "^4.0.0",
- "decode-named-character-reference": "^1.0.0",
- "devlop": "^1.0.0",
- "micromark-core-commonmark": "^2.0.0",
- "micromark-factory-space": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-chunked": "^2.0.0",
- "micromark-util-combine-extensions": "^2.0.0",
- "micromark-util-decode-numeric-character-reference": "^2.0.0",
- "micromark-util-encode": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0",
- "micromark-util-resolve-all": "^2.0.0",
- "micromark-util-sanitize-uri": "^2.0.0",
- "micromark-util-subtokenize": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-core-commonmark": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz",
- "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==",
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "dependencies": {
- "decode-named-character-reference": "^1.0.0",
- "devlop": "^1.0.0",
- "micromark-factory-destination": "^2.0.0",
- "micromark-factory-label": "^2.0.0",
- "micromark-factory-space": "^2.0.0",
- "micromark-factory-title": "^2.0.0",
- "micromark-factory-whitespace": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-chunked": "^2.0.0",
- "micromark-util-classify-character": "^2.0.0",
- "micromark-util-html-tag-name": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0",
- "micromark-util-resolve-all": "^2.0.0",
- "micromark-util-subtokenize": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-extension-gfm": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
- "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
- "dependencies": {
- "micromark-extension-gfm-autolink-literal": "^2.0.0",
- "micromark-extension-gfm-footnote": "^2.0.0",
- "micromark-extension-gfm-strikethrough": "^2.0.0",
- "micromark-extension-gfm-table": "^2.0.0",
- "micromark-extension-gfm-tagfilter": "^2.0.0",
- "micromark-extension-gfm-task-list-item": "^2.0.0",
- "micromark-util-combine-extensions": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/micromark-extension-gfm-autolink-literal": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz",
- "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==",
- "dependencies": {
- "micromark-util-character": "^2.0.0",
- "micromark-util-sanitize-uri": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/micromark-extension-gfm-footnote": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz",
- "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==",
- "dependencies": {
- "devlop": "^1.0.0",
- "micromark-core-commonmark": "^2.0.0",
- "micromark-factory-space": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0",
- "micromark-util-sanitize-uri": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/micromark-extension-gfm-strikethrough": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz",
- "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==",
- "dependencies": {
- "devlop": "^1.0.0",
- "micromark-util-chunked": "^2.0.0",
- "micromark-util-classify-character": "^2.0.0",
- "micromark-util-resolve-all": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/micromark-extension-gfm-table": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz",
- "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==",
- "dependencies": {
- "devlop": "^1.0.0",
- "micromark-factory-space": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/micromark-extension-gfm-tagfilter": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
- "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
- "dependencies": {
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/micromark-extension-gfm-task-list-item": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz",
- "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==",
- "dependencies": {
- "devlop": "^1.0.0",
- "micromark-factory-space": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
"node_modules/micromark-factory-destination": {
@@ -14750,24 +13151,16 @@
}
},
"node_modules/mlly": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz",
- "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.11.3",
- "pathe": "^1.1.2",
- "pkg-types": "^1.0.3",
- "ufo": "^1.3.2"
- }
- },
- "node_modules/mri": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
- "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
- "dev": true,
- "engines": {
- "node": ">=4"
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz",
+ "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.3",
+ "pathe": "^1.1.2",
+ "pkg-types": "^1.1.1",
+ "ufo": "^1.5.3"
}
},
"node_modules/ms": {
@@ -14808,12 +13201,6 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -14964,13 +13351,14 @@
}
},
"node_modules/object-is": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
- "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
+ "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
@@ -15006,86 +13394,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/object.entries": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
- "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.fromentries": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
- "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.groupby": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
- "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.hasown": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz",
- "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==",
- "dev": true,
- "dependencies": {
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.values": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
- "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -15201,23 +13509,6 @@
"node": ">=8"
}
},
- "node_modules/optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
- "dev": true,
- "dependencies": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/ora": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
@@ -15271,21 +13562,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/p-map": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
@@ -15505,13 +13781,15 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
"integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/pathval": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "*"
}
@@ -15526,7 +13804,8 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.0",
@@ -15574,24 +13853,25 @@
}
},
"node_modules/pkg-types": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
- "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz",
+ "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "jsonc-parser": "^3.2.0",
- "mlly": "^1.2.0",
- "pathe": "^1.1.0"
+ "confbox": "^0.1.7",
+ "mlly": "^1.7.1",
+ "pathe": "^1.1.2"
}
},
"node_modules/playwright": {
- "version": "1.47.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.0.tgz",
- "integrity": "sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==",
+ "version": "1.47.2",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz",
+ "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.47.0"
+ "playwright-core": "1.47.2"
},
"bin": {
"playwright": "cli.js"
@@ -15604,9 +13884,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.47.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.0.tgz",
- "integrity": "sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==",
+ "version": "1.47.2",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz",
+ "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -15796,253 +14076,8 @@
},
"node_modules/postcss-value-parser": {
"version": "4.2.0",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/prettier": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
- "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
- "dev": true,
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/prettier-eslint": {
- "version": "16.3.0",
- "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-16.3.0.tgz",
- "integrity": "sha512-Lh102TIFCr11PJKUMQ2kwNmxGhTsv/KzUg9QYF2Gkw259g/kPgndZDWavk7/ycbRvj2oz4BPZ1gCU8bhfZH/Xg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/parser": "^6.7.5",
- "common-tags": "^1.4.0",
- "dlv": "^1.1.0",
- "eslint": "^8.7.0",
- "indent-string": "^4.0.0",
- "lodash.merge": "^4.6.0",
- "loglevel-colored-level-prefix": "^1.0.0",
- "prettier": "^3.0.1",
- "pretty-format": "^29.7.0",
- "require-relative": "^0.8.7",
- "typescript": "^5.2.2",
- "vue-eslint-parser": "^9.1.0"
- },
- "engines": {
- "node": ">=16.10.0"
- },
- "peerDependencies": {
- "prettier-plugin-svelte": "^3.0.0",
- "svelte-eslint-parser": "*"
- },
- "peerDependenciesMeta": {
- "prettier-plugin-svelte": {
- "optional": true
- },
- "svelte-eslint-parser": {
- "optional": true
- }
- }
- },
- "node_modules/prettier-eslint/node_modules/@typescript-eslint/parser": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
- "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "6.21.0",
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/typescript-estree": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/prettier-eslint/node_modules/@typescript-eslint/scope-manager": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
- "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/prettier-eslint/node_modules/@typescript-eslint/types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
- "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
- "dev": true,
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/prettier-eslint/node_modules/@typescript-eslint/typescript-estree": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
- "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "minimatch": "9.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/prettier-eslint/node_modules/@typescript-eslint/visitor-keys": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
- "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "6.21.0",
- "eslint-visitor-keys": "^3.4.1"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/prettier-eslint/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/prettier-eslint/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/prettier-eslint/node_modules/minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/prettier-eslint/node_modules/prettier": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
- "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
- "dev": true,
- "bin": {
- "prettier": "bin/prettier.cjs"
- },
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/prettier-eslint/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/prettier-eslint/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/prettier-eslint/node_modules/semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
"node_modules/pretty-bytes": {
"version": "5.6.0",
@@ -16061,6 +14096,7 @@
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -16075,6 +14111,7 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -16086,95 +14123,8 @@
"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/pretty-quick": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.3.1.tgz",
- "integrity": "sha512-3b36UXfYQ+IXXqex6mCca89jC8u0mYLqFAN5eTQKoXO6oCQYcIVYZEB/5AlBHI7JPYygReM2Vv6Vom/Gln7fBg==",
- "dev": true,
- "dependencies": {
- "execa": "^4.1.0",
- "find-up": "^4.1.0",
- "ignore": "^5.3.0",
- "mri": "^1.2.0",
- "picocolors": "^1.0.0",
- "picomatch": "^3.0.1",
- "tslib": "^2.6.2"
- },
- "bin": {
- "pretty-quick": "dist/cli.js"
- },
- "engines": {
- "node": ">=10.13"
- },
- "peerDependencies": {
- "prettier": "^2.0.0"
- }
- },
- "node_modules/pretty-quick/node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/pretty-quick/node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/pretty-quick/node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/pretty-quick/node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/pretty-quick/node_modules/picomatch": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
- "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==",
"dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
+ "license": "MIT"
},
"node_modules/prismjs": {
"version": "1.29.0",
@@ -16262,12 +14212,13 @@
}
},
"node_modules/qs": {
- "version": "6.10.4",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz",
- "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==",
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
- "side-channel": "^1.0.4"
+ "side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -16780,27 +14731,6 @@
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
- "node_modules/reflect.getprototypeof": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
- "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.1",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "globalthis": "^1.0.3",
- "which-builtin-type": "^1.1.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -17046,12 +14976,6 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
- "node_modules/require-relative": {
- "version": "0.8.7",
- "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
- "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==",
- "dev": true
- },
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -17083,15 +15007,6 @@
"node": ">=8"
}
},
- "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,
- "funding": {
- "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
- }
- },
"node_modules/response-iterator": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz",
@@ -17129,21 +15044,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/rollup": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
@@ -17225,24 +15125,6 @@
"tslib": "^2.1.0"
}
},
- "node_modules/safe-array-concat": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
- "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "get-intrinsic": "^1.2.4",
- "has-symbols": "^1.0.3",
- "isarray": "^2.0.5"
- },
- "engines": {
- "node": ">=0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -17263,23 +15145,6 @@
}
]
},
- "node_modules/safe-regex-test": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
- "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-regex": "^1.1.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -17464,7 +15329,8 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/signal-exit": {
"version": "3.0.7",
@@ -17561,6 +15427,7 @@
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
"integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
@@ -17585,7 +15452,8 @@
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/std-env": {
"version": "3.7.0",
@@ -17598,6 +15466,7 @@
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
"integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"internal-slot": "^1.0.4"
},
@@ -17665,81 +15534,6 @@
"node": ">=8"
}
},
- "node_modules/string.prototype.matchall": {
- "version": "4.0.11",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
- "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.0.1",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.7",
- "regexp.prototype.flags": "^1.5.2",
- "set-function-name": "^2.0.2",
- "side-channel": "^1.0.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trim": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
- "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.0",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
- "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
- "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/stringify-entities": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz",
@@ -17776,15 +15570,6 @@
"node": ">=8"
}
},
- "node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/strip-final-newline": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
@@ -17794,18 +15579,6 @@
"node": ">=6"
}
},
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/strip-literal": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz",
@@ -18149,12 +15922,6 @@
"node": ">=8"
}
},
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -18195,16 +15962,18 @@
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
},
"node_modules/tinybench": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz",
- "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==",
- "dev": true
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/tinypool": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.3.tgz",
- "integrity": "sha512-Ud7uepAklqRH1bvwy22ynrliC7Dljz7Tm8M/0RBUW+YRa4YHhZ6e4PpgE+fu1zr/WqB1kbeuVrdfeuyIBpy4tw==",
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz",
+ "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=14.0.0"
}
@@ -18214,6 +15983,7 @@
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz",
"integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=14.0.0"
}
@@ -18228,15 +15998,13 @@
}
},
"node_modules/tmp": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
- "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+ "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
"dev": true,
- "dependencies": {
- "rimraf": "^3.0.0"
- },
+ "license": "MIT",
"engines": {
- "node": ">=8.17.0"
+ "node": ">=14.14"
}
},
"node_modules/to-fast-properties": {
@@ -18335,18 +16103,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/ts-api-utils": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
- "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
- "dev": true,
- "engines": {
- "node": ">=16"
- },
- "peerDependencies": {
- "typescript": ">=4.2.0"
- }
- },
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -18373,7 +16129,8 @@
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -18416,7 +16173,8 @@
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"node_modules/ts-toolbelt": {
"version": "9.6.0",
@@ -18435,36 +16193,12 @@
"node": "^18 || >=20"
},
"peerDependencies": {
- "typescript": "^5.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/tsconfig-paths": {
- "version": "3.15.0",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
- "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
- "dev": true,
- "dependencies": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.2",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- }
- },
- "node_modules/tsconfig-paths/node_modules/json5": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
- "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
- "dev": true,
- "dependencies": {
- "minimist": "^1.2.0"
+ "typescript": "^5.0.0"
},
- "bin": {
- "json5": "lib/cli.js"
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
"node_modules/tslib": {
@@ -18477,6 +16211,7 @@
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
},
@@ -18488,25 +16223,15 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
- "dev": true
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
+ "license": "Unlicense"
},
"node_modules/type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
+ "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
@@ -18523,79 +16248,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/typed-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
- "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "es-errors": "^1.3.0",
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/typed-array-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
- "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-byte-offset": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
- "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
- "dev": true,
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-length": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
- "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13",
- "possible-typed-array-names": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/types-ramda": {
"version": "0.29.10",
"resolved": "https://registry.npmjs.org/types-ramda/-/types-ramda-0.29.10.tgz",
@@ -18618,32 +16270,6 @@
"node": ">=14.17"
}
},
- "node_modules/typescript-eslint": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz",
- "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/eslint-plugin": "7.16.0",
- "@typescript-eslint/parser": "7.16.0",
- "@typescript-eslint/utils": "7.16.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.56.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
"node_modules/ua-parser-js": {
"version": "1.0.37",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
@@ -18673,10 +16299,11 @@
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/ufo": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz",
- "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==",
- "dev": true
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
+ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/uglify-js": {
"version": "3.17.4",
@@ -18690,21 +16317,6 @@
"node": ">=0.8.0"
}
},
- "node_modules/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/unc-path-regex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
@@ -19062,6 +16674,7 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
+ "license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
@@ -19070,7 +16683,8 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"node_modules/v8-to-istanbul": {
"version": "9.2.0",
@@ -19103,6 +16717,7 @@
"engines": [
"node >=0.6.0"
],
+ "license": "MIT",
"dependencies": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
@@ -19221,6 +16836,7 @@
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz",
"integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.3.4",
@@ -19261,6 +16877,7 @@
"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz",
"integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@vitest/expect": "1.4.0",
"@vitest/runner": "1.4.0",
@@ -19326,6 +16943,7 @@
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^8.0.1",
@@ -19349,6 +16967,7 @@
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=16"
},
@@ -19361,6 +16980,7 @@
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": ">=16.17.0"
}
@@ -19370,6 +16990,7 @@
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
@@ -19382,6 +17003,7 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -19394,6 +17016,7 @@
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^4.0.0"
},
@@ -19409,6 +17032,7 @@
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"mimic-fn": "^4.0.0"
},
@@ -19424,6 +17048,7 @@
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -19436,6 +17061,7 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
+ "license": "ISC",
"engines": {
"node": ">=14"
},
@@ -19448,6 +17074,7 @@
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -19460,42 +17087,6 @@
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
},
- "node_modules/vue-eslint-parser": {
- "version": "9.4.3",
- "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
- "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==",
- "dev": true,
- "dependencies": {
- "debug": "^4.3.4",
- "eslint-scope": "^7.1.1",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.3.1",
- "esquery": "^1.4.0",
- "lodash": "^4.17.21",
- "semver": "^7.3.6"
- },
- "engines": {
- "node": "^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=6.0.0"
- }
- },
- "node_modules/vue-eslint-parser/node_modules/semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/w3c-keyname": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
@@ -19539,11 +17130,6 @@
"node": ">= 8"
}
},
- "node_modules/web-vitals": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz",
- "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg=="
- },
"node_modules/webcrypto-core": {
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.9.tgz",
@@ -19642,32 +17228,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/which-builtin-type": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz",
- "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==",
- "dev": true,
- "dependencies": {
- "function.prototype.name": "^1.1.5",
- "has-tostringtag": "^1.0.0",
- "is-async-function": "^2.0.0",
- "is-date-object": "^1.0.5",
- "is-finalizationregistry": "^1.0.2",
- "is-generator-function": "^1.0.10",
- "is-regex": "^1.1.4",
- "is-weakref": "^1.0.2",
- "isarray": "^2.0.5",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.9"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/which-collection": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
@@ -19709,10 +17269,11 @@
}
},
"node_modules/why-is-node-running": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
- "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"siginfo": "^2.0.0",
"stackback": "0.0.2"
@@ -19875,7 +17436,8 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=6"
}
@@ -19916,12 +17478,6 @@
}
},
"dependencies": {
- "@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
- "dev": true
- },
"@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
@@ -21375,6 +18931,78 @@
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
"dev": true
},
+ "@biomejs/biome": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.3.tgz",
+ "integrity": "sha512-POjAPz0APAmX33WOQFGQrwLvlu7WLV4CFJMlB12b6ZSg+2q6fYu9kZwLCOA+x83zXfcPd1RpuWOKJW0GbBwLIQ==",
+ "dev": true,
+ "requires": {
+ "@biomejs/cli-darwin-arm64": "1.9.3",
+ "@biomejs/cli-darwin-x64": "1.9.3",
+ "@biomejs/cli-linux-arm64": "1.9.3",
+ "@biomejs/cli-linux-arm64-musl": "1.9.3",
+ "@biomejs/cli-linux-x64": "1.9.3",
+ "@biomejs/cli-linux-x64-musl": "1.9.3",
+ "@biomejs/cli-win32-arm64": "1.9.3",
+ "@biomejs/cli-win32-x64": "1.9.3"
+ }
+ },
+ "@biomejs/cli-darwin-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.3.tgz",
+ "integrity": "sha512-QZzD2XrjJDUyIZK+aR2i5DDxCJfdwiYbUKu9GzkCUJpL78uSelAHAPy7m0GuPMVtF/Uo+OKv97W3P9nuWZangQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@biomejs/cli-darwin-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.3.tgz",
+ "integrity": "sha512-vSCoIBJE0BN3SWDFuAY/tRavpUtNoqiceJ5PrU3xDfsLcm/U6N93JSM0M9OAiC/X7mPPfejtr6Yc9vSgWlEgVw==",
+ "dev": true,
+ "optional": true
+ },
+ "@biomejs/cli-linux-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.3.tgz",
+ "integrity": "sha512-vJkAimD2+sVviNTbaWOGqEBy31cW0ZB52KtpVIbkuma7PlfII3tsLhFa+cwbRAcRBkobBBhqZ06hXoZAN8NODQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@biomejs/cli-linux-arm64-musl": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.3.tgz",
+ "integrity": "sha512-VBzyhaqqqwP3bAkkBrhVq50i3Uj9+RWuj+pYmXrMDgjS5+SKYGE56BwNw4l8hR3SmYbLSbEo15GcV043CDSk+Q==",
+ "dev": true,
+ "optional": true
+ },
+ "@biomejs/cli-linux-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.3.tgz",
+ "integrity": "sha512-x220V4c+romd26Mu1ptU+EudMXVS4xmzKxPVb9mgnfYlN4Yx9vD5NZraSx/onJnd3Gh/y8iPUdU5CDZJKg9COA==",
+ "dev": true,
+ "optional": true
+ },
+ "@biomejs/cli-linux-x64-musl": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.3.tgz",
+ "integrity": "sha512-TJmnOG2+NOGM72mlczEsNki9UT+XAsMFAOo8J0me/N47EJ/vkLXxf481evfHLlxMejTY6IN8SdRSiPVLv6AHlA==",
+ "dev": true,
+ "optional": true
+ },
+ "@biomejs/cli-win32-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.3.tgz",
+ "integrity": "sha512-lg/yZis2HdQGsycUvHWSzo9kOvnGgvtrYRgoCEwPBwwAL8/6crOp3+f47tPwI/LI1dZrhSji7PNsGKGHbwyAhw==",
+ "dev": true,
+ "optional": true
+ },
+ "@biomejs/cli-win32-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.3.tgz",
+ "integrity": "sha512-cQMy2zanBkVLpmmxXdK6YePzmZx0s5Z7KEnwmrW54rcXK3myCNbQa09SwGZ8i/8sLw0H9F3X7K4rxVNGU8/D4Q==",
+ "dev": true,
+ "optional": true
+ },
"@codemirror/autocomplete": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.2.0.tgz",
@@ -21569,7 +19197,8 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@jridgewell/trace-mapping": "0.3.9"
},
@@ -21578,7 +19207,8 @@
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
@@ -21587,9 +19217,9 @@
}
},
"@cypress/request": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz",
- "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==",
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.5.tgz",
+ "integrity": "sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==",
"dev": true,
"requires": {
"aws-sign2": "~0.7.0",
@@ -21598,31 +19228,18 @@
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "http-signature": "~1.3.6",
+ "form-data": "~4.0.0",
+ "http-signature": "~1.4.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"performance-now": "^2.1.0",
- "qs": "6.10.4",
+ "qs": "6.13.0",
"safe-buffer": "^5.1.2",
"tough-cookie": "^4.1.3",
"tunnel-agent": "^0.6.0",
"uuid": "^8.3.2"
- },
- "dependencies": {
- "form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dev": true,
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- }
}
},
"@cypress/xvfb": {
@@ -21776,83 +19393,28 @@
"optional": true
},
"@esbuild/sunos-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
- "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
- "optional": true
- },
- "@esbuild/win32-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
- "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
- "optional": true
- },
- "@esbuild/win32-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
- "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
- "optional": true
- },
- "@esbuild/win32-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
- "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
- "optional": true
- },
- "@eslint-community/eslint-utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
- "dev": true,
- "requires": {
- "eslint-visitor-keys": "^3.3.0"
- }
- },
- "@eslint-community/regexpp": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
- "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
- "dev": true
- },
- "@eslint/eslintrc": {
- "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.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "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"
- }
- },
- "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
- }
- }
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "optional": true
},
- "@eslint/js": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
- "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
- "dev": true
+ "@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "optional": true
+ },
+ "@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "optional": true
+ },
+ "@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "optional": true
},
"@floating-ui/core": {
"version": "1.6.0",
@@ -22706,41 +20268,18 @@
"integrity": "sha512-U410sAr92xgxT1idlu9WWOVjndxLdgPUHEB8Schr27C9eh7/xUnITWpCMF93s+lGiG++D4JnbSnrb5A21AdSNg==",
"requires": {}
},
- "@humanwhocodes/config-array": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
- "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
- "dev": true,
- "requires": {
- "@humanwhocodes/object-schema": "^2.0.2",
- "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": "2.0.2",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
- "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
- "dev": true
- },
"@iconify-icon/react": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@iconify-icon/react/-/react-2.0.1.tgz",
- "integrity": "sha512-1m6L2yNsSJ25k5baQRqNqh2J0w+91PwOn1WdBIR6ZTwxePbsZC8k3NNVc6m9BJObsIQdUlMA1NGj8el4tfbsVg==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@iconify-icon/react/-/react-2.1.0.tgz",
+ "integrity": "sha512-OuEsW5Y474rg3WlseLFQ0uuJjnyk1DhLN1Ire5JGjF4sF8/rNxGJDLSItEogRcKuUbL+zzuoBsaTUVVInuixRA==",
"requires": {
- "iconify-icon": "^2.0.0"
+ "iconify-icon": "^2.1.0"
}
},
"@iconify-json/mdi": {
- "version": "1.1.64",
- "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.1.64.tgz",
- "integrity": "sha512-zGeo5TjhNFAY6FmSDBLAzDO811t77r6v/mDi7CAL9w5eXqKez6bIjk8R9AL/RHIeq44ALP4Ozr4lMqFTkHr7ug==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.2.0.tgz",
+ "integrity": "sha512-E9/3l5Syg3wfuarorFodhn4s8YorxhH3U3U20LaNBNiqw1kFNIDWhF6HymuzAD35k7RH0OBasJ+ZUyFtVVV6eg==",
"requires": {
"@iconify/types": "*"
}
@@ -22844,9 +20383,9 @@
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
},
"@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
},
"@jridgewell/trace-mapping": {
"version": "0.3.25",
@@ -23083,12 +20622,12 @@
"optional": true
},
"@playwright/test": {
- "version": "1.47.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.0.tgz",
- "integrity": "sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==",
+ "version": "1.47.2",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.2.tgz",
+ "integrity": "sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ==",
"dev": true,
"requires": {
- "playwright": "1.47.0"
+ "playwright": "1.47.2"
}
},
"@popperjs/core": {
@@ -23809,9 +21348,9 @@
}
},
"@testing-library/react": {
- "version": "14.2.2",
- "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.2.tgz",
- "integrity": "sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==",
+ "version": "14.3.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz",
+ "integrity": "sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.12.5",
@@ -23828,25 +21367,29 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"@types/aria-query": {
"version": "5.0.4",
@@ -24000,12 +21543,6 @@
"integrity": "sha512-b7bq23s4fgBB76n34m2b3RBf6M369B0Z9uRR8aHTMd8kZISRkmDEpPD8hhpYvDFzr3bJCPES96cm3Q6qRNDbQw==",
"dev": true
},
- "@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
- "dev": true
- },
"@types/loadable__component": {
"version": "5.13.9",
"resolved": "https://registry.npmjs.org/@types/loadable__component/-/loadable__component-5.13.9.tgz",
@@ -24160,128 +21697,6 @@
"@types/node": "*"
}
},
- "@typescript-eslint/eslint-plugin": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz",
- "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==",
- "dev": true,
- "requires": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "7.16.0",
- "@typescript-eslint/type-utils": "7.16.0",
- "@typescript-eslint/utils": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0",
- "graphemer": "^1.4.0",
- "ignore": "^5.3.1",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^1.3.0"
- }
- },
- "@typescript-eslint/parser": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz",
- "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/scope-manager": "7.16.0",
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/typescript-estree": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0",
- "debug": "^4.3.4"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz",
- "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0"
- }
- },
- "@typescript-eslint/type-utils": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz",
- "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/typescript-estree": "7.16.0",
- "@typescript-eslint/utils": "7.16.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^1.3.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz",
- "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==",
- "dev": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz",
- "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/visitor-keys": "7.16.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^1.3.0"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- },
- "semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
- "dev": true
- }
- }
- },
- "@typescript-eslint/utils": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz",
- "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==",
- "dev": true,
- "requires": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "7.16.0",
- "@typescript-eslint/types": "7.16.0",
- "@typescript-eslint/typescript-estree": "7.16.0"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz",
- "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "7.16.0",
- "eslint-visitor-keys": "^3.4.3"
- }
- },
"@uiw/color-convert": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@uiw/color-convert/-/color-convert-2.1.1.tgz",
@@ -24576,9 +21991,9 @@
}
},
"yocto-queue": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
- "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
+ "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
"dev": true
}
}
@@ -24612,9 +22027,9 @@
}
},
"react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "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
}
}
@@ -24667,9 +22082,9 @@
}
},
"react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "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
}
}
@@ -24744,13 +22159,6 @@
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"devOptional": true
},
- "acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "requires": {}
- },
"acorn-walk": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
@@ -24776,18 +22184,6 @@
"indent-string": "^4.0.0"
}
},
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
"ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@@ -24873,119 +22269,12 @@
"is-array-buffer": "^3.0.4"
}
},
- "array-includes": {
- "version": "3.1.8",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
- "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "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.findlast": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
- "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-shim-unscopables": "^1.0.2"
- }
- },
- "array.prototype.findlastindex": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
- "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-shim-unscopables": "^1.0.2"
- }
- },
- "array.prototype.flat": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
- "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "array.prototype.flatmap": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
- "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "array.prototype.toreversed": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz",
- "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
- }
- },
- "array.prototype.tosorted": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz",
- "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.5",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.22.3",
- "es-errors": "^1.1.0",
- "es-shim-unscopables": "^1.0.2"
- }
- },
- "arraybuffer.prototype.slice": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
- "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
- "dev": true,
- "requires": {
- "array-buffer-byte-length": "^1.0.1",
- "call-bind": "^1.0.5",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.22.3",
- "es-errors": "^1.2.1",
- "get-intrinsic": "^1.2.3",
- "is-array-buffer": "^3.0.4",
- "is-shared-array-buffer": "^1.0.2"
- }
- },
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -25083,9 +22372,9 @@
"dev": true
},
"aws4": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
- "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
+ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==",
"dev": true
},
"babel-plugin-polyfill-corejs2": {
@@ -25273,47 +22562,6 @@
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
"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.0.1",
- "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
- "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
- "dev": true,
- "requires": {
- "semver": "^7.0.0"
- },
- "dependencies": {
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
- },
"busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
@@ -25374,9 +22622,9 @@
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
},
"caniuse-lite": {
- "version": "1.0.30001605",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz",
- "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ=="
+ "version": "1.0.30001664",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz",
+ "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g=="
},
"capital-case": {
"version": "1.0.4",
@@ -25401,9 +22649,9 @@
"integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="
},
"chai": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
- "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz",
+ "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
"dev": true,
"requires": {
"assertion-error": "^1.1.0",
@@ -25412,7 +22660,7 @@
"get-func-name": "^2.0.2",
"loupe": "^2.3.6",
"pathval": "^1.1.1",
- "type-detect": "^4.0.8"
+ "type-detect": "^4.1.0"
}
},
"chalk": {
@@ -25651,6 +22899,15 @@
"integrity": "sha512-1prg2gv44sYfpHscP26uLT/ePrh0mlmVwMSoSd3zYKQ92Ab3jPRLzyCnpyOCQLJbK+YdNs4HvMRqMNYdy4pMhA==",
"requires": {}
},
+ "cmdk": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz",
+ "integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==",
+ "requires": {
+ "@radix-ui/react-dialog": "1.0.5",
+ "@radix-ui/react-primitive": "1.0.3"
+ }
+ },
"codemirror": {
"version": "5.65.16",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz",
@@ -25717,6 +22974,12 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "confbox": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz",
+ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
+ "dev": true
+ },
"constant-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
@@ -25770,7 +23033,8 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"crelt": {
"version": "1.0.6",
@@ -25879,12 +23143,12 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"cypress": {
- "version": "13.7.3",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.3.tgz",
- "integrity": "sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==",
+ "version": "13.15.0",
+ "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz",
+ "integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==",
"dev": true,
"requires": {
- "@cypress/request": "^3.0.0",
+ "@cypress/request": "^3.0.4",
"@cypress/xvfb": "^1.2.4",
"@types/sinonjs__fake-timers": "8.1.1",
"@types/sizzle": "^2.3.2",
@@ -25923,7 +23187,7 @@
"request-progress": "^3.0.0",
"semver": "^7.5.3",
"supports-color": "^8.1.1",
- "tmp": "~0.2.1",
+ "tmp": "~0.2.3",
"untildify": "^4.0.0",
"yauzl": "^2.10.0"
},
@@ -26092,39 +23356,6 @@
"whatwg-url": "^14.0.0"
}
},
- "data-view-buffer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
- "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- }
- },
- "data-view-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
- "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- }
- },
- "data-view-byte-offset": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
- "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- }
- },
"dataloader": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz",
@@ -26187,9 +23418,9 @@
"integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ=="
},
"deep-eql": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
- "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz",
+ "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==",
"dev": true,
"requires": {
"type-detect": "^4.0.0"
@@ -26219,13 +23450,7 @@
"which-boxed-primitive": "^1.0.2",
"which-collection": "^1.0.1",
"which-typed-array": "^1.1.13"
- }
- },
- "deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
+ }
},
"deepmerge": {
"version": "4.3.1",
@@ -26281,816 +23506,267 @@
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="
},
"detect-indent": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
- "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
- "dev": true
- },
- "detect-libc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
- "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
- "dev": true,
- "optional": true,
- "peer": true
- },
- "detect-node-es": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
- "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
- },
- "devlop": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
- "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
- "requires": {
- "dequal": "^2.0.0"
- }
- },
- "didyoumean": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
- "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
- },
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "devOptional": true
- },
- "diff-match-patch": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
- "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
- },
- "diff-sequences": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
- "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
- "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"
- }
- },
- "dlv": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
- "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "dom-accessibility-api": {
- "version": "0.5.16",
- "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
- "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
- "dev": true
- },
- "dom-helpers": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
- "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
- "requires": {
- "@babel/runtime": "^7.8.7",
- "csstype": "^3.0.2"
- }
- },
- "dom-serializer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
- "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
- "requires": {
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.2",
- "entities": "^4.2.0"
- }
- },
- "domelementtype": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
- "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
- },
- "domhandler": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
- "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
- "requires": {
- "domelementtype": "^2.3.0"
- }
- },
- "domutils": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
- "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
- "requires": {
- "dom-serializer": "^2.0.0",
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.3"
- }
- },
- "dot-case": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
- "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
- "requires": {
- "no-case": "^3.0.4",
- "tslib": "^2.0.3"
- }
- },
- "dotenv": {
- "version": "16.4.5",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
- "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
- "dev": true
- },
- "dset": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
- "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
- "dev": true
- },
- "eastasianwidth": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
- "dev": true,
- "requires": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "electron-to-chromium": {
- "version": "1.4.724",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.724.tgz",
- "integrity": "sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA=="
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
- },
- "end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "dev": true,
- "requires": {
- "once": "^1.4.0"
- }
- },
- "enquirer": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
- "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
- "dev": true,
- "requires": {
- "ansi-colors": "^4.1.1",
- "strip-ansi": "^6.0.1"
- }
- },
- "entities": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
- "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
- },
- "environment": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
- "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
- "dev": true
- },
- "error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "requires": {
- "is-arrayish": "^0.2.1"
- }
- },
- "es-abstract": {
- "version": "1.23.3",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
- "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
- "dev": true,
- "requires": {
- "array-buffer-byte-length": "^1.0.1",
- "arraybuffer.prototype.slice": "^1.0.3",
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "data-view-buffer": "^1.0.1",
- "data-view-byte-length": "^1.0.1",
- "data-view-byte-offset": "^1.0.0",
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-set-tostringtag": "^2.0.3",
- "es-to-primitive": "^1.2.1",
- "function.prototype.name": "^1.1.6",
- "get-intrinsic": "^1.2.4",
- "get-symbol-description": "^1.0.2",
- "globalthis": "^1.0.3",
- "gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.0.3",
- "has-symbols": "^1.0.3",
- "hasown": "^2.0.2",
- "internal-slot": "^1.0.7",
- "is-array-buffer": "^3.0.4",
- "is-callable": "^1.2.7",
- "is-data-view": "^1.0.1",
- "is-negative-zero": "^2.0.3",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.3",
- "is-string": "^1.0.7",
- "is-typed-array": "^1.1.13",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.13.1",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.5",
- "regexp.prototype.flags": "^1.5.2",
- "safe-array-concat": "^1.1.2",
- "safe-regex-test": "^1.0.3",
- "string.prototype.trim": "^1.2.9",
- "string.prototype.trimend": "^1.0.8",
- "string.prototype.trimstart": "^1.0.8",
- "typed-array-buffer": "^1.0.2",
- "typed-array-byte-length": "^1.0.1",
- "typed-array-byte-offset": "^1.0.2",
- "typed-array-length": "^1.0.6",
- "unbox-primitive": "^1.0.2",
- "which-typed-array": "^1.1.15"
- }
- },
- "es-define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
- "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
- "dev": true,
- "requires": {
- "get-intrinsic": "^1.2.4"
- }
- },
- "es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true
- },
- "es-get-iterator": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
- "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "has-symbols": "^1.0.3",
- "is-arguments": "^1.1.1",
- "is-map": "^2.0.2",
- "is-set": "^2.0.2",
- "is-string": "^1.0.7",
- "isarray": "^2.0.5",
- "stop-iteration-iterator": "^1.0.0"
- }
- },
- "es-iterator-helpers": {
- "version": "1.0.18",
- "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz",
- "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.0",
- "es-errors": "^1.3.0",
- "es-set-tostringtag": "^2.0.3",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "globalthis": "^1.0.3",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.0.3",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.7",
- "iterator.prototype": "^1.1.2",
- "safe-array-concat": "^1.1.2"
- }
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
+ "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
+ "dev": true
},
- "es-object-atoms": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
- "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"dev": true,
- "requires": {
- "es-errors": "^1.3.0"
- }
+ "optional": true,
+ "peer": true
},
- "es-set-tostringtag": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
- "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
- "dev": true,
- "requires": {
- "get-intrinsic": "^1.2.4",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.1"
- }
+ "detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
},
- "es-shim-unscopables": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
- "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
- "dev": true,
+ "devlop": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
+ "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
"requires": {
- "hasown": "^2.0.0"
+ "dequal": "^2.0.0"
}
},
- "es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "dev": true,
- "requires": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- }
+ "didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
},
- "esbuild": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
- "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
- "requires": {
- "@esbuild/aix-ppc64": "0.21.5",
- "@esbuild/android-arm": "0.21.5",
- "@esbuild/android-arm64": "0.21.5",
- "@esbuild/android-x64": "0.21.5",
- "@esbuild/darwin-arm64": "0.21.5",
- "@esbuild/darwin-x64": "0.21.5",
- "@esbuild/freebsd-arm64": "0.21.5",
- "@esbuild/freebsd-x64": "0.21.5",
- "@esbuild/linux-arm": "0.21.5",
- "@esbuild/linux-arm64": "0.21.5",
- "@esbuild/linux-ia32": "0.21.5",
- "@esbuild/linux-loong64": "0.21.5",
- "@esbuild/linux-mips64el": "0.21.5",
- "@esbuild/linux-ppc64": "0.21.5",
- "@esbuild/linux-riscv64": "0.21.5",
- "@esbuild/linux-s390x": "0.21.5",
- "@esbuild/linux-x64": "0.21.5",
- "@esbuild/netbsd-x64": "0.21.5",
- "@esbuild/openbsd-x64": "0.21.5",
- "@esbuild/sunos-x64": "0.21.5",
- "@esbuild/win32-arm64": "0.21.5",
- "@esbuild/win32-ia32": "0.21.5",
- "@esbuild/win32-x64": "0.21.5"
- }
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "optional": true,
+ "peer": true
},
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
+ "diff-match-patch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
+ "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
},
- "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==",
+ "diff-sequences": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
"dev": true
},
- "eslint": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
- "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "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": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.0",
- "@humanwhocodes/config-array": "^0.11.14",
- "@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.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.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",
- "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",
- "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.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
- },
- "dependencies": {
- "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"
- }
- },
- "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"
- }
- },
- "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
- }
+ "path-type": "^4.0.0"
}
},
- "eslint-compat-utils": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz",
- "integrity": "sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==",
- "dev": true,
- "requires": {
- "semver": "^7.5.4"
- },
- "dependencies": {
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
- }
+ "dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
},
- "eslint-config-prettier": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
- "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
- "dev": true,
- "requires": {}
+ "dom-accessibility-api": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
+ "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
+ "dev": true
},
- "eslint-import-resolver-node": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
- "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
- "dev": true,
+ "dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"requires": {
- "debug": "^3.2.7",
- "is-core-module": "^2.13.0",
- "resolve": "^1.22.4"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
}
},
- "eslint-module-utils": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
- "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
- "dev": true,
+ "dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"requires": {
- "debug": "^3.2.7"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
}
},
- "eslint-plugin-cypress": {
- "version": "2.15.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz",
- "integrity": "sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w==",
- "dev": true,
+ "domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
+ },
+ "domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"requires": {
- "globals": "^13.20.0"
- },
- "dependencies": {
- "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"
- }
- },
- "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
- }
+ "domelementtype": "^2.3.0"
}
},
- "eslint-plugin-es-x": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.6.0.tgz",
- "integrity": "sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==",
- "dev": true,
+ "domutils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
+ "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"requires": {
- "@eslint-community/eslint-utils": "^4.1.2",
- "@eslint-community/regexpp": "^4.6.0",
- "eslint-compat-utils": "^0.5.0"
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
}
},
- "eslint-plugin-import": {
- "version": "2.29.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
- "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
- "dev": true,
+ "dot-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+ "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
"requires": {
- "array-includes": "^3.1.7",
- "array.prototype.findlastindex": "^1.2.3",
- "array.prototype.flat": "^1.3.2",
- "array.prototype.flatmap": "^1.3.2",
- "debug": "^3.2.7",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.9",
- "eslint-module-utils": "^2.8.0",
- "hasown": "^2.0.0",
- "is-core-module": "^2.13.1",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.fromentries": "^2.0.7",
- "object.groupby": "^1.0.1",
- "object.values": "^1.1.7",
- "semver": "^6.3.1",
- "tsconfig-paths": "^3.15.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- }
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
}
},
- "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==",
+ "dotenv": {
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+ "dev": true
+ },
+ "dset": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
+ "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
+ "dev": true
+ },
+ "eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
"dev": true,
"requires": {
- "@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": {
- "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"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "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
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- }
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
}
},
- "eslint-plugin-promise": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz",
- "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==",
- "dev": true,
- "requires": {}
+ "electron-to-chromium": {
+ "version": "1.4.724",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.724.tgz",
+ "integrity": "sha512-RTRvkmRkGhNBPPpdrgtDKvmOEYTrPlXDfc0J/Nfq5s29tEahAwhiX4mmhNzj6febWMleulxVYPh7QwCSL/EldA=="
},
- "eslint-plugin-react": {
- "version": "7.34.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz",
- "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==",
- "dev": true,
- "requires": {
- "array-includes": "^3.1.7",
- "array.prototype.findlast": "^1.2.4",
- "array.prototype.flatmap": "^1.3.2",
- "array.prototype.toreversed": "^1.1.2",
- "array.prototype.tosorted": "^1.1.3",
- "doctrine": "^2.1.0",
- "es-iterator-helpers": "^1.0.17",
- "estraverse": "^5.3.0",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.7",
- "object.fromentries": "^2.0.7",
- "object.hasown": "^1.1.3",
- "object.values": "^1.1.7",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.5",
- "semver": "^6.3.1",
- "string.prototype.matchall": "^4.0.10"
- },
- "dependencies": {
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "resolve": {
- "version": "2.0.0-next.5",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
- "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
- "dev": true,
- "requires": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- }
- }
- }
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
- "eslint-plugin-unused-imports": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz",
- "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==",
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true,
"requires": {
- "eslint-rule-composer": "^0.3.0"
+ "once": "^1.4.0"
}
},
- "eslint-rule-composer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz",
- "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==",
- "dev": true
- },
- "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==",
+ "enquirer": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
"dev": true,
"requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
+ "ansi-colors": "^4.1.1",
+ "strip-ansi": "^6.0.1"
}
},
- "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==",
+ "entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
+ },
+ "environment": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
+ "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
"dev": true
},
- "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,
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"requires": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "is-arrayish": "^0.2.1"
}
},
- "esquery": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
- "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+ "es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"dev": true,
"requires": {
- "estraverse": "^5.1.0"
+ "get-intrinsic": "^1.2.4"
}
},
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true
+ },
+ "es-get-iterator": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
+ "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
"dev": true,
"requires": {
- "estraverse": "^5.2.0"
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.1.3",
+ "has-symbols": "^1.0.3",
+ "is-arguments": "^1.1.1",
+ "is-map": "^2.0.2",
+ "is-set": "^2.0.2",
+ "is-string": "^1.0.7",
+ "isarray": "^2.0.5",
+ "stop-iteration-iterator": "^1.0.0"
+ }
+ },
+ "esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "requires": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
}
},
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
+ "escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
"estree-util-is-identifier-name": {
"version": "3.0.0",
@@ -27225,18 +23901,6 @@
"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",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
"fast-querystring": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz",
@@ -27330,15 +23994,6 @@
}
}
},
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -27352,33 +24007,6 @@
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz",
"integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng=="
},
- "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": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
- "dev": true,
- "requires": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.2.9",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
- "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
- "dev": true
- },
"for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -27461,18 +24089,6 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
},
- "function.prototype.name": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
- "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "functions-have-names": "^1.2.3"
- }
- },
"functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
@@ -27529,26 +24145,6 @@
"pump": "^3.0.0"
}
},
- "get-symbol-description": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
- "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.5",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4"
- }
- },
- "get-tsconfig": {
- "version": "4.7.3",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz",
- "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==",
- "dev": true,
- "requires": {
- "resolve-pkg-maps": "^1.0.0"
- }
- },
"getos": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
@@ -27608,15 +24204,6 @@
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
- "globalthis": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
- "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
- "dev": true,
- "requires": {
- "define-properties": "^1.1.3"
- }
- },
"globby": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
@@ -27651,12 +24238,6 @@
"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
- },
"graphiql": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/graphiql/-/graphiql-3.1.2.tgz",
@@ -27760,23 +24341,6 @@
"wordwrap": "^1.0.0"
}
},
- "has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true
- }
- }
- },
"has-bigints": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
@@ -27911,14 +24475,14 @@
}
},
"http-signature": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz",
- "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz",
+ "integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==",
"dev": true,
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^2.0.2",
- "sshpk": "^1.14.1"
+ "sshpk": "^1.18.0"
}
},
"https-proxy-agent": {
@@ -27944,9 +24508,9 @@
"dev": true
},
"iconify-icon": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-2.0.0.tgz",
- "integrity": "sha512-38ArOkxmyD9oDbJBkxaFpE6eZ0K3F9Sk+3x4mWGfjMJaxi3EKrix9Du4iWhgBFT3imKC4FJJE34ur2Rc7Xm+Uw==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-2.1.0.tgz",
+ "integrity": "sha512-lto4XU3bwTQnb+D/CsJ4dWAo0aDe+uPMxEtxyOodw9l7R9QnJUUab3GCehlw2M8mDHdeUu/ufx8PvRQiJphhXg==",
"requires": {
"@iconify/types": "^2.0.0"
}
@@ -28000,12 +24564,6 @@
"integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==",
"dev": true
},
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true
- },
"indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
@@ -28141,15 +24699,6 @@
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
},
- "is-async-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
- "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
"is-bigint": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
@@ -28177,15 +24726,6 @@
"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",
@@ -28209,15 +24749,6 @@
"hasown": "^2.0.0"
}
},
- "is-data-view": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
- "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
- "dev": true,
- "requires": {
- "is-typed-array": "^1.1.13"
- }
- },
"is-date-object": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
@@ -28234,32 +24765,14 @@
},
"is-extglob": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
- },
- "is-finalizationregistry": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
- "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2"
- }
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
- "is-generator-function": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
- "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
"is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -28304,12 +24817,6 @@
"integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
"dev": true
},
- "is-negative-zero": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
- "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
- "dev": true
- },
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -28412,15 +24919,6 @@
"has-symbols": "^1.0.2"
}
},
- "is-typed-array": {
- "version": "1.1.13",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
- "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
- "dev": true,
- "requires": {
- "which-typed-array": "^1.1.14"
- }
- },
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -28457,15 +24955,6 @@
"integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
"dev": true
},
- "is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2"
- }
- },
"is-weakset": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
@@ -28554,19 +25043,6 @@
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
"integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg=="
},
- "iterator.prototype": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
- "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==",
- "dev": true,
- "requires": {
- "define-properties": "^1.2.1",
- "get-intrinsic": "^1.2.1",
- "has-symbols": "^1.0.3",
- "reflect.getprototypeof": "^1.0.4",
- "set-function-name": "^2.0.1"
- }
- },
"jackspeak": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
@@ -28588,9 +25064,9 @@
"dev": true
},
"jotai": {
- "version": "2.7.2",
- "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.7.2.tgz",
- "integrity": "sha512-6Ft5kpNu8p93Ssf1Faoza3hYQZRIYp7rioK8MwTTFnbQKwUyZElwquPwl1h6U0uo9hC0jr+ghO3gcSjc6P35/Q==",
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.10.0.tgz",
+ "integrity": "sha512-8W4u0aRlOIwGlLQ0sqfl/c6+eExl5D8lZgAUolirZLktyaj4WnxO/8a0HEPmtriQAB6X5LMhXzZVmw02X0P0qQ==",
"requires": {}
},
"js-levenshtein": {
@@ -28652,12 +25128,6 @@
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
},
- "json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true
- },
"json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -28669,12 +25139,6 @@
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
"dev": true
},
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
"json-stable-stringify": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz",
@@ -28687,12 +25151,6 @@
"object-keys": "^1.1.1"
}
},
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -28719,12 +25177,6 @@
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
},
- "jsonc-parser": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
- "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==",
- "dev": true
- },
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -28753,43 +25205,12 @@
"verror": "1.10.0"
}
},
- "jsx-ast-utils": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
- "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
- "dev": true,
- "requires": {
- "array-includes": "^3.1.6",
- "array.prototype.flat": "^1.3.1",
- "object.assign": "^4.1.4",
- "object.values": "^1.1.6"
- }
- },
- "keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
- "dev": true,
- "requires": {
- "json-buffer": "3.0.1"
- }
- },
"lazy-ass": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
"integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
"dev": true
},
- "levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- }
- },
"lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -29124,15 +25545,6 @@
"pkg-types": "^1.0.3"
}
},
- "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": {
- "p-locate": "^5.0.0"
- }
- },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -29149,12 +25561,6 @@
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
"dev": true
},
- "lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@@ -29202,70 +25608,6 @@
}
}
},
- "loglevel": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz",
- "integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==",
- "dev": true
- },
- "loglevel-colored-level-prefix": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz",
- "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "loglevel": "^1.4.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true
- },
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
- "dev": true
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- }
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- },
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
- "dev": true
- }
- }
- },
"longest-streak": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
@@ -29320,12 +25662,12 @@
"dev": true
},
"magic-string": {
- "version": "0.30.8",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
- "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
+ "version": "0.30.11",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
+ "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
"dev": true,
"requires": {
- "@jridgewell/sourcemap-codec": "^1.4.15"
+ "@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"magicast": {
@@ -29378,7 +25720,8 @@
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"map-cache": {
"version": "0.2.2",
@@ -29997,23 +26340,17 @@
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ=="
},
"mlly": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz",
- "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==",
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz",
+ "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==",
"dev": true,
"requires": {
"acorn": "^8.11.3",
"pathe": "^1.1.2",
- "pkg-types": "^1.0.3",
- "ufo": "^1.3.2"
+ "pkg-types": "^1.1.1",
+ "ufo": "^1.5.3"
}
},
- "mri": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
- "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
- "dev": true
- },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -30040,12 +26377,6 @@
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g=="
},
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
"neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -30163,13 +26494,13 @@
"dev": true
},
"object-is": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
- "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
+ "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
"dev": true,
"requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1"
}
},
"object-keys": {
@@ -30190,62 +26521,6 @@
"object-keys": "^1.1.1"
}
},
- "object.entries": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
- "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- }
- },
- "object.fromentries": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
- "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- }
- },
- "object.groupby": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
- "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2"
- }
- },
- "object.hasown": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz",
- "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==",
- "dev": true,
- "requires": {
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- }
- },
- "object.values": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
- "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- }
- },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -30329,20 +26604,6 @@
}
}
},
- "optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
- "dev": true,
- "requires": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
- }
- },
"ora": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
@@ -30381,15 +26642,6 @@
"yocto-queue": "^0.1.0"
}
},
- "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": {
- "p-limit": "^3.0.2"
- }
- },
"p-map": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
@@ -30605,24 +26857,24 @@
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="
},
"pkg-types": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
- "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz",
+ "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==",
"dev": true,
"requires": {
- "jsonc-parser": "^3.2.0",
- "mlly": "^1.2.0",
- "pathe": "^1.1.0"
+ "confbox": "^0.1.7",
+ "mlly": "^1.7.1",
+ "pathe": "^1.1.2"
}
},
"playwright": {
- "version": "1.47.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.0.tgz",
- "integrity": "sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==",
+ "version": "1.47.2",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz",
+ "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==",
"dev": true,
"requires": {
"fsevents": "2.3.2",
- "playwright-core": "1.47.0"
+ "playwright-core": "1.47.2"
},
"dependencies": {
"fsevents": {
@@ -30635,9 +26887,9 @@
}
},
"playwright-core": {
- "version": "1.47.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.0.tgz",
- "integrity": "sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==",
+ "version": "1.47.2",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz",
+ "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==",
"dev": true
},
"pluralize": {
@@ -30702,175 +26954,33 @@
"dependencies": {
"lilconfig": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz",
- "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g=="
- }
- }
- },
- "postcss-nested": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
- "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
- "requires": {
- "postcss-selector-parser": "^6.0.11"
- }
- },
- "postcss-selector-parser": {
- "version": "6.0.15",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
- "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
- "requires": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "postcss-value-parser": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true
- },
- "prettier": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
- "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
- "dev": true
- },
- "prettier-eslint": {
- "version": "16.3.0",
- "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-16.3.0.tgz",
- "integrity": "sha512-Lh102TIFCr11PJKUMQ2kwNmxGhTsv/KzUg9QYF2Gkw259g/kPgndZDWavk7/ycbRvj2oz4BPZ1gCU8bhfZH/Xg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/parser": "^6.7.5",
- "common-tags": "^1.4.0",
- "dlv": "^1.1.0",
- "eslint": "^8.7.0",
- "indent-string": "^4.0.0",
- "lodash.merge": "^4.6.0",
- "loglevel-colored-level-prefix": "^1.0.0",
- "prettier": "^3.0.1",
- "pretty-format": "^29.7.0",
- "require-relative": "^0.8.7",
- "typescript": "^5.2.2",
- "vue-eslint-parser": "^9.1.0"
- },
- "dependencies": {
- "@typescript-eslint/parser": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
- "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
- "dev": true,
- "requires": {
- "@typescript-eslint/scope-manager": "6.21.0",
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/typescript-estree": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0",
- "debug": "^4.3.4"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
- "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
- "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
- "dev": true
- },
- "@typescript-eslint/typescript-estree": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
- "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "minimatch": "9.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
- "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
- "dev": true,
- "requires": {
- "@typescript-eslint/types": "6.21.0",
- "eslint-visitor-keys": "^3.4.1"
- }
- },
- "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
- },
- "brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- },
- "prettier": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
- "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
- "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==",
- "dev": true,
- "requires": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.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==",
- "dev": true
- },
- "semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
- "dev": true
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz",
+ "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g=="
}
}
},
+ "postcss-nested": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+ "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "requires": {
+ "postcss-selector-parser": "^6.0.11"
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "6.0.15",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz",
+ "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==",
+ "requires": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ }
+ },
+ "postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+ },
"pretty-bytes": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@@ -30902,66 +27012,6 @@
}
}
},
- "pretty-quick": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.3.1.tgz",
- "integrity": "sha512-3b36UXfYQ+IXXqex6mCca89jC8u0mYLqFAN5eTQKoXO6oCQYcIVYZEB/5AlBHI7JPYygReM2Vv6Vom/Gln7fBg==",
- "dev": true,
- "requires": {
- "execa": "^4.1.0",
- "find-up": "^4.1.0",
- "ignore": "^5.3.0",
- "mri": "^1.2.0",
- "picocolors": "^1.0.0",
- "picomatch": "^3.0.1",
- "tslib": "^2.6.2"
- },
- "dependencies": {
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "picomatch": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
- "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==",
- "dev": true
- }
- }
- },
"prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
@@ -31035,12 +27085,12 @@
"dev": true
},
"qs": {
- "version": "6.10.4",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz",
- "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==",
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dev": true,
"requires": {
- "side-channel": "^1.0.4"
+ "side-channel": "^1.0.6"
}
},
"query-string": {
@@ -31379,21 +27429,6 @@
"decimal.js-light": "^2.4.1"
}
},
- "reflect.getprototypeof": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
- "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.1",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "globalthis": "^1.0.3",
- "which-builtin-type": "^1.1.3"
- }
- },
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -31583,12 +27618,6 @@
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
- "require-relative": {
- "version": "0.8.7",
- "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
- "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==",
- "dev": true
- },
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -31611,12 +27640,6 @@
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"dev": true
},
- "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
- },
"response-iterator": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz",
@@ -31643,15 +27666,6 @@
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"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"
- }
- },
"rollup": {
"version": "4.22.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
@@ -31706,35 +27720,12 @@
"tslib": "^2.1.0"
}
},
- "safe-array-concat": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
- "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "get-intrinsic": "^1.2.4",
- "has-symbols": "^1.0.3",
- "isarray": "^2.0.5"
- }
- },
"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==",
"dev": true
},
- "safe-regex-test": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
- "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.6",
- "es-errors": "^1.3.0",
- "is-regex": "^1.1.4"
- }
- },
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -32035,60 +28026,6 @@
"strip-ansi": "^6.0.1"
}
},
- "string.prototype.matchall": {
- "version": "4.0.11",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
- "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.0.1",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.7",
- "regexp.prototype.flags": "^1.5.2",
- "set-function-name": "^2.0.2",
- "side-channel": "^1.0.6"
- }
- },
- "string.prototype.trim": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
- "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.0",
- "es-object-atoms": "^1.0.0"
- }
- },
- "string.prototype.trimend": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
- "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- }
- },
- "string.prototype.trimstart": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
- "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- }
- },
"stringify-entities": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz",
@@ -32114,24 +28051,12 @@
"ansi-regex": "^5.0.1"
}
},
- "strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true
- },
"strip-final-newline": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
"dev": true
},
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true
- },
"strip-literal": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz",
@@ -32382,12 +28307,6 @@
"minimatch": "^3.0.4"
}
},
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
"thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -32422,15 +28341,15 @@
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
},
"tinybench": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz",
- "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
"dev": true
},
"tinypool": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.3.tgz",
- "integrity": "sha512-Ud7uepAklqRH1bvwy22ynrliC7Dljz7Tm8M/0RBUW+YRa4YHhZ6e4PpgE+fu1zr/WqB1kbeuVrdfeuyIBpy4tw==",
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz",
+ "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==",
"dev": true
},
"tinyspy": {
@@ -32449,13 +28368,10 @@
}
},
"tmp": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
- "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
- "dev": true,
- "requires": {
- "rimraf": "^3.0.0"
- }
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+ "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+ "dev": true
},
"to-fast-properties": {
"version": "2.0.0",
@@ -32528,13 +28444,6 @@
"resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz",
"integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g=="
},
- "ts-api-utils": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
- "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
- "dev": true,
- "requires": {}
- },
"ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -32558,7 +28467,8 @@
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
- "devOptional": true,
+ "optional": true,
+ "peer": true,
"requires": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -32579,7 +28489,8 @@
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
- "devOptional": true
+ "optional": true,
+ "peer": true
}
}
},
@@ -32595,29 +28506,6 @@
"integrity": "sha512-CMjc5zMnyAjcS9sPLytrbFmj89st2g+JYtY/c02ug4Q+CZaAtCgbyviI0n1YvjZE/pzoc6FbNsINS13DOL1B9w==",
"requires": {}
},
- "tsconfig-paths": {
- "version": "3.15.0",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
- "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
- "dev": true,
- "requires": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.2",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
- "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.0"
- }
- }
- }
- },
"tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@@ -32638,19 +28526,10 @@
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
"dev": true
},
- "type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1"
- }
- },
"type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz",
+ "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==",
"dev": true
},
"type-fest": {
@@ -32659,58 +28538,6 @@
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
"dev": true
},
- "typed-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
- "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "es-errors": "^1.3.0",
- "is-typed-array": "^1.1.13"
- }
- },
- "typed-array-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
- "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13"
- }
- },
- "typed-array-byte-offset": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
- "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
- "dev": true,
- "requires": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13"
- }
- },
- "typed-array-length": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
- "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13",
- "possible-typed-array-names": "^1.0.0"
- }
- },
"types-ramda": {
"version": "0.29.10",
"resolved": "https://registry.npmjs.org/types-ramda/-/types-ramda-0.29.10.tgz",
@@ -32726,17 +28553,6 @@
"integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==",
"devOptional": true
},
- "typescript-eslint": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz",
- "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==",
- "dev": true,
- "requires": {
- "@typescript-eslint/eslint-plugin": "7.16.0",
- "@typescript-eslint/parser": "7.16.0",
- "@typescript-eslint/utils": "7.16.0"
- }
- },
"ua-parser-js": {
"version": "1.0.37",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
@@ -32749,9 +28565,9 @@
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"ufo": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz",
- "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==",
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
+ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
"dev": true
},
"uglify-js": {
@@ -32760,18 +28576,6 @@
"integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
"optional": true
},
- "unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- }
- },
"unc-path-regex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
@@ -33021,7 +28825,8 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"v8-to-istanbul": {
"version": "9.2.0",
@@ -33237,29 +29042,6 @@
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
},
- "vue-eslint-parser": {
- "version": "9.4.3",
- "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
- "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==",
- "dev": true,
- "requires": {
- "debug": "^4.3.4",
- "eslint-scope": "^7.1.1",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.3.1",
- "esquery": "^1.4.0",
- "lodash": "^4.17.21",
- "semver": "^7.3.6"
- },
- "dependencies": {
- "semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
- "dev": true
- }
- }
- },
"w3c-keyname": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
@@ -33297,11 +29079,6 @@
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"dev": true
},
- "web-vitals": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz",
- "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg=="
- },
"webcrypto-core": {
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.9.tgz",
@@ -33378,26 +29155,6 @@
"is-symbol": "^1.0.3"
}
},
- "which-builtin-type": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz",
- "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==",
- "dev": true,
- "requires": {
- "function.prototype.name": "^1.1.5",
- "has-tostringtag": "^1.0.0",
- "is-async-function": "^2.0.0",
- "is-date-object": "^1.0.5",
- "is-finalizationregistry": "^1.0.2",
- "is-generator-function": "^1.0.10",
- "is-regex": "^1.1.4",
- "is-weakref": "^1.0.2",
- "isarray": "^2.0.5",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.9"
- }
- },
"which-collection": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
@@ -33430,9 +29187,9 @@
}
},
"why-is-node-running": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
- "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dev": true,
"requires": {
"siginfo": "^2.0.0",
@@ -33549,7 +29306,8 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
- "devOptional": true
+ "optional": true,
+ "peer": true
},
"yocto-queue": {
"version": "0.1.0",
diff --git a/frontend/app/package.json b/frontend/app/package.json
index 9ad1a9f3fc..35890d8acb 100644
--- a/frontend/app/package.json
+++ b/frontend/app/package.json
@@ -23,11 +23,8 @@
"cypress:run": "npm run cypress:run:component",
"cypress:run:component": "cypress run --component",
"cypress:run:spec": "ELECTRON_ENABLE_LOGGING=1 cypress run --spec",
- "prettier": "prettier './**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc.json",
- "prettier:fix": "prettier --write './**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc.json",
- "eslint": "eslint .",
- "eslint:fix": "eslint . --fix",
- "format-code": "npm run prettier:fix && npm run eslint:fix"
+ "biome": "biome check .",
+ "biome:fix": "biome check --apply ."
},
"dependencies": {
"@apollo/client": "^3.9.10",
@@ -40,8 +37,8 @@
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.3",
"@hookform/error-message": "^2.0.1",
- "@iconify-icon/react": "^2.0.1",
- "@iconify-json/mdi": "^1.1.64",
+ "@iconify-icon/react": "^2.1.0",
+ "@iconify-json/mdi": "^1.2.0",
"@popperjs/core": "^2.11.8",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
@@ -58,12 +55,13 @@
"clsx": "^2.1.0",
"cm6-graphql": "^0.0.14",
"cm6-theme-basic-light": "^0.2.0",
+ "cmdk": "^1.0.0",
"cross-fetch": "^4.0.0",
"date-fns": "^3.6.0",
"graphiql": "^3.1.2",
"graphql": "^16.8.1",
"handlebars": "^4.7.8",
- "jotai": "^2.7.2",
+ "jotai": "^2.10.0",
"json-to-graphql-query": "^2.2.5",
"prismjs": "^1.29.0",
"query-string": "^9.0.0",
@@ -91,13 +89,13 @@
"unidiff": "^1.0.4",
"use-query-params": "^2.2.1",
"vite": "^5.2.8",
- "vite-tsconfig-paths": "^4.3.2",
- "web-vitals": "^2.1.4"
+ "vite-tsconfig-paths": "^4.3.2"
},
"devDependencies": {
+ "@biomejs/biome": "1.9.3",
"@graphql-codegen/cli": "^5.0.2",
"@graphql-codegen/typescript": "^4.0.9",
- "@playwright/test": "^1.47.0",
+ "@playwright/test": "^1.47.2",
"@testing-library/react": "^14.2.2",
"@types/loadable__component": "^5.13.9",
"@types/node": "^20.12.3",
@@ -108,30 +106,16 @@
"@types/react-dom": "^18.2.23",
"@types/react-test-renderer": "^18.0.7",
"@types/sha1": "^1.1.5",
- "@typescript-eslint/eslint-plugin": "^7.16.0",
"@vitest/coverage-v8": "^1.4.0",
- "cypress": "^13.7.2",
- "eslint": "^8.57.0",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-cypress": "^2.15.1",
- "eslint-plugin-import": "^2.29.1",
- "eslint-plugin-n": "^16.6.2",
- "eslint-plugin-promise": "^6.1.1",
- "eslint-plugin-react": "^7.34.1",
- "eslint-plugin-unused-imports": "^3.2.0",
+ "cypress": "^13.15.0",
"husky": "^8.0.3",
"jsdom": "^24.0.0",
"lint-staged": "^15.2.10",
"openapi-typescript": "^7.0.2",
"postcss": "^8.4.23",
- "prettier": "2.8.8",
- "prettier-eslint": "^16.3.0",
- "pretty-quick": "^3.1.3",
"react-test-renderer": "^18.2.0",
"tailwindcss": "^3.4.3",
- "ts-node": "^10.9.2",
"typescript": "^5.5.3",
- "typescript-eslint": "^7.16.0",
"vitest": "^1.4.0"
},
"overrides": {
@@ -146,15 +130,7 @@
}
},
"browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
+ "production": [">0.2%", "not dead", "not op_mini all"],
+ "development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"]
}
}
diff --git a/frontend/app/src/App.tsx b/frontend/app/src/App.tsx
index a911334429..c8e4bc3957 100644
--- a/frontend/app/src/App.tsx
+++ b/frontend/app/src/App.tsx
@@ -3,21 +3,25 @@ import { ErrorBoundary } from "react-error-boundary";
import { RouterProvider } from "react-router-dom";
import { Slide, ToastContainer } from "react-toastify";
-import { ApolloProvider } from "@apollo/client";
import graphqlClient from "@/graphql/graphqlClientApollo";
import { AuthProvider } from "@/hooks/useAuth";
import { router } from "@/router";
import ErrorFallback from "@/screens/errors/error-fallback";
import { store } from "@/state";
+import { ApolloProvider } from "@apollo/client";
+import { addCollection } from "@iconify-icon/react";
+import mdiIcons from "@iconify-json/mdi/icons.json";
import "./styles/index.css";
import "react-toastify/dist/ReactToastify.css";
+addCollection(mdiIcons);
+
export function App() {
return (
-
-
+
+
-
-
+
+
);
}
diff --git a/frontend/app/src/Root.tsx b/frontend/app/src/Root.tsx
index 381f9091c2..f431fe73f1 100644
--- a/frontend/app/src/Root.tsx
+++ b/frontend/app/src/Root.tsx
@@ -1,17 +1,11 @@
import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { CONFIG } from "@/config/config";
+import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import { fetchUrl } from "@/utils/fetch";
import { useSetAtom } from "jotai";
import { ReactNode, useEffect, useState } from "react";
import { toast } from "react-toastify";
-import reportWebVitals from "./reportWebVitals";
import { Config, configState } from "./state/atoms/config.atom";
-import LoadingScreen from "@/screens/loading-screen/loading-screen";
-import { fetchUrl } from "@/utils/fetch";
-
-import { addCollection } from "@iconify-icon/react";
-import mdiIcons from "@iconify-json/mdi/icons.json";
-
-addCollection(mdiIcons);
export const Root = ({ children }: { children?: ReactNode }) => {
const setConfig = useSetAtom(configState);
@@ -63,8 +57,3 @@ export const Root = ({ children }: { children?: ReactNode }) => {
return children;
};
-
-// If you want to start measuring performance in your app, pass a function
-// to log results (for example: reportWebVitals(console.log))
-// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-reportWebVitals();
diff --git a/frontend/app/src/components/account-menu.tsx b/frontend/app/src/components/account-menu.tsx
index f9b4412526..e37cf2d67c 100644
--- a/frontend/app/src/components/account-menu.tsx
+++ b/frontend/app/src/components/account-menu.tsx
@@ -1,111 +1,200 @@
+import { Button } from "@/components/buttons/button-primitive";
import { Avatar } from "@/components/display/avatar";
+import { Skeleton } from "@/components/skeleton";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuDivider,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { INFRAHUB_DOC_LOCAL, INFRAHUB_GITHUB_URL, INFRAHUB_SWAGGER_DOC_URL } from "@/config/config";
+import { ACCOUNT_GENERIC_OBJECT } from "@/config/constants";
import { getProfileDetails } from "@/graphql/queries/accounts/getProfileDetails";
import { useAuth } from "@/hooks/useAuth";
-import useQuery from "@/hooks/useQuery";
-import { userNavigation } from "@/screens/layout/navigation-list";
-import { genericsState, IModelSchema } from "@/state/atoms/schema.atom";
-import { classNames } from "@/utils/common";
-import { gql } from "@apollo/client";
-import { Menu, Transition } from "@headlessui/react";
-import { Fragment, useEffect } from "react";
+import { AppVersion } from "@/screens/layout/app-version";
+import { IModelSchema, genericsState } from "@/state/atoms/schema.atom";
+import { constructPath } from "@/utils/fetch";
+import { gql, useQuery } from "@apollo/client";
+import { Icon } from "@iconify-icon/react";
+import { useAtomValue } from "jotai";
+import { useEffect } from "react";
import { Link, useLocation } from "react-router-dom";
-import { useAtomValue } from "jotai/index";
-import { ACCOUNT_OBJECT } from "@/config/constants";
import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
-
-const customId = "profile-alert";
export const AccountMenu = () => {
- const { isAuthenticated } = useAuth();
-
- const location = useLocation();
+ const { isAuthenticated, signOut } = useAuth();
const generics = useAtomValue(genericsState);
- const schema = generics.find((s) => s.kind === ACCOUNT_OBJECT);
+ const schema = generics.find((s) => s.kind === ACCOUNT_GENERIC_OBJECT);
if (!isAuthenticated) {
- return (
-
- Sign in
-
- );
+ return ;
}
if (!schema) {
- return ;
+ return ;
}
- return ;
+ return ;
};
-const AccountAvatarWithMenu = ({ schema }: { schema: IModelSchema }) => {
- const { signOut } = useAuth();
+const CommonMenuItems = () => (
+ <>
+
+
+
+ GitHub Repository
+
+
+
+
+
+
+ Infrahub documentation
+
+
+
+
+
+
+ GraphQL Sandbox
+
+
+
+
+
+
+ Swagger documentation
+
+
+ >
+);
+
+const UnauthenticatedAccountMenu = () => {
+ const location = useLocation();
+
+ return (
+
+
+
+
+
+
+
+ Log in
+ anonymous
+
+ {
+ event.preventDefault();
+ }}
+ asChild
+ >
+
+
+
+
+
+
+
+
+
+
+ Log in
+
+
+
+
+
+
+ );
+};
+
+const AuthenticatedAccountMenu = ({
+ schema,
+ signOut,
+}: {
+ schema: IModelSchema;
+ signOut: () => void;
+}) => {
const query = gql(getProfileDetails({ ...schema }));
const { error, loading, data } = useQuery(query);
useEffect(() => {
if (error) {
toast(, {
- toastId: customId,
+ toastId: "profile-alert",
});
-
- // Sign out because there is nothing from the API for that user id
signOut();
}
- }, [error]);
+ }, [error, signOut]);
- if (loading || !schema) {
- return ;
+ if (loading) {
+ return ;
}
const profile = data?.AccountProfile;
return (
-
+
+
+
+
+
+
+
+
+
+ Account settings
+
+
+
+
+
+
+
+ Logout
+
+
+
+
+
+ );
+};
+
+const AccountMenuSkeleton = () => {
+ return (
+
);
};
diff --git a/frontend/app/src/components/branch-selector.tsx b/frontend/app/src/components/branch-selector.tsx
index a73f503747..29521dd781 100644
--- a/frontend/app/src/components/branch-selector.tsx
+++ b/frontend/app/src/components/branch-selector.tsx
@@ -1,132 +1,188 @@
-import { DateDisplay } from "@/components/display/date-display";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { QSP } from "@/config/qsp";
import { Branch } from "@/generated/graphql";
import { usePermission } from "@/hooks/usePermission";
import { branchesState, currentBranchAtom } from "@/state/atoms/branches.atom";
import { branchesToSelectOptions } from "@/utils/branches";
-import { classNames } from "@/utils/common";
import { Icon } from "@iconify-icon/react";
import { useAtomValue } from "jotai/index";
-import React from "react";
+import React, { useEffect, useState } from "react";
import { StringParam, useQueryParam } from "use-query-params";
-import { ButtonWithTooltip } from "./buttons/button-primitive";
-import { SelectButton } from "./buttons/select-button";
+import { ComboboxItem } from "@/components/ui/combobox";
+import { Command, CommandEmpty, CommandInput, CommandList } from "@/components/ui/command";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { constructPath } from "@/utils/fetch";
+import { useSetAtom } from "jotai";
+import { Button, ButtonWithTooltip, LinkButton } from "./buttons/button-primitive";
import BranchCreateForm from "./form/branch-create-form";
-import { SelectOption } from "./inputs/select";
-
-const getBranchIcon = (branch: Branch | null, active?: Boolean) =>
- branch && (
- <>
- {branch.has_schema_changes && (
-
- )}
-
- {branch.is_default && (
-
- )}
-
- {branch.sync_with_git && (
-
- )}
- >
- );
export default function BranchSelector() {
- const branches = useAtomValue(branchesState);
- const branch = useAtomValue(currentBranchAtom);
- const [, setBranchInQueryString] = useQueryParam(QSP.BRANCH, StringParam);
+ const currentBranch = useAtomValue(currentBranchAtom);
+ const [isOpen, setIsOpen] = useState(false);
+ const [displayForm, setDisplayForm] = useState(false);
- const valueLabel = (
-
- {getBranchIcon(branch, true)}
+ useEffect(() => {
+ if (isOpen) graphqlClient.refetchQueries({ include: ["GetBranches"] });
+ }, [isOpen]);
-
{branch?.name}
-
+ return (
+ {
+ setDisplayForm(false);
+ setIsOpen(open);
+ }}
+ >
+
+
+
+
+
+ {displayForm ? (
+ {
+ setDisplayForm(false);
+ }}
+ onSuccess={() => {
+ setDisplayForm(false);
+ setIsOpen(false);
+ }}
+ data-testid="branch-create-form"
+ />
+ ) : (
+
+ )}
+
+
);
+}
- const branchesOptions: SelectOption[] = branchesToSelectOptions(branches);
+function BranchSelect({
+ setPopoverOpen,
+ setFormOpen,
+}: {
+ setPopoverOpen: (open: boolean) => void;
+ setFormOpen: (open: boolean) => void;
+}) {
+ const branches = useAtomValue(branchesState);
+ const setCurrentBranch = useSetAtom(currentBranchAtom);
+ const [, setBranchInQueryString] = useQueryParam(QSP.BRANCH, StringParam);
- const onBranchChange = (branch: Branch) => {
- if (branch?.is_default) {
- // undefined is needed to remove a parameter from the QSP
- setBranchInQueryString(undefined);
+ const handleBranchChange = (branch: Branch) => {
+ if (branch.is_default) {
+ setBranchInQueryString(undefined); // undefined is needed to remove a parameter from the QSP
} else {
setBranchInQueryString(branch.name);
}
+ setCurrentBranch(branch);
+ setPopoverOpen(false);
};
- const renderOption = ({ option, active, selected }: any) => (
-
-
{getBranchIcon(option, active)}
-
-
-
{option.name}
- {selected ? (
-
-
-
- ) : null}
+ return (
+ <>
+
+
+
+
+
+
+
+
+ No branch found
+ {branchesToSelectOptions(branches).map((branch) => (
+ handleBranchChange(branch)}
+ />
+ ))}
+
+
+
+ setPopoverOpen(false)}
+ >
+ View all branches
+
-
- {option?.created_at &&
}
-
+ >
);
+}
- /**
- * There's always a main branch present at least.
- */
- if (!branches.length) {
- return null;
- }
+function BranchOption({ branch, onChange }: { branch: Branch; onChange: () => void }) {
+ const currentBranch = useAtomValue(currentBranchAtom);
return (
-
-
-
-
-
+
+
+
{branch.name}
+
+
+ {branch.is_default && (
+ default
+ )}
+ {branch.sync_with_git && (
+
+ )}
+
+
+
);
}
-export const BranchFormTrigger = () => {
+export const BranchFormTriggerButton = ({ setOpen }: { setOpen: (open: boolean) => void }) => {
const permission = usePermission();
- const [open, setOpen] = React.useState(false);
return (
-
-
-
-
-
-
-
-
-
-
- setOpen(false)} onSuccess={() => setOpen(false)} />
-
-
+
{
+ if (e.key === "Enter") {
+ e.stopPropagation();
+ setOpen(true);
+ }
+ }}
+ onClick={(e) => {
+ e.stopPropagation();
+ setOpen(true);
+ }}
+ data-testid="create-branch-button"
+ >
+
+
);
};
diff --git a/frontend/app/src/components/buttons/button-primitive.tsx b/frontend/app/src/components/buttons/button-primitive.tsx
index 537df4a76a..2d2943105e 100644
--- a/frontend/app/src/components/buttons/button-primitive.tsx
+++ b/frontend/app/src/components/buttons/button-primitive.tsx
@@ -1,13 +1,13 @@
+import { Spinner } from "@/components/ui/spinner";
import { focusStyle } from "@/components/ui/style";
import { Tooltip, TooltipProps } from "@/components/ui/tooltip";
import { classNames } from "@/utils/common";
-import { cva, type VariantProps } from "class-variance-authority";
+import { type VariantProps, cva } from "class-variance-authority";
import { ButtonHTMLAttributes, forwardRef } from "react";
import { Link, LinkProps } from "react-router-dom";
-import { Spinner } from "@/components/ui/spinner";
const buttonVariants = cva(
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium disabled:opacity-60 disabled:cursor-not-allowed",
+ "inline-flex items-center justify-center whitespace-nowrap rounded text-sm font-medium disabled:opacity-60 disabled:cursor-not-allowed",
{
variants: {
variant: {
@@ -25,7 +25,7 @@ const buttonVariants = cva(
xs: "h-7 px-2 text-xs",
sm: "h-7 px-2 text-sm",
icon: "h-7 w-7 rounded-full",
- square: "h-9 w-9 rounded-md",
+ square: "h-9 w-9",
},
},
defaultVariants: {
@@ -48,7 +48,8 @@ export const Button = forwardRef
(
type={type}
className={classNames(focusStyle, buttonVariants({ variant, size, className }))}
ref={ref}
- {...props}>
+ {...props}
+ >
{isLoading && }
{children}
diff --git a/frontend/app/src/components/buttons/button.tsx b/frontend/app/src/components/buttons/button.tsx
index ada844957c..d25b4f4002 100644
--- a/frontend/app/src/components/buttons/button.tsx
+++ b/frontend/app/src/components/buttons/button.tsx
@@ -107,7 +107,8 @@ export const Button = forwardRef((props: ButtonProps, ref: any) => {
className={classNames(DEFAULT_CLASS(className, buttonType), customClassName, className)}
{...propsToPass}
onClick={handleClick}
- disabled={isLoading ? true : propsToPass.disabled}>
+ disabled={isLoading ? true : propsToPass.disabled}
+ >
{isLoading && }
{!isLoading && children}
diff --git a/frontend/app/src/components/buttons/retry.tsx b/frontend/app/src/components/buttons/retry.tsx
index 4ce2ee4fa4..15bd14e18f 100644
--- a/frontend/app/src/components/buttons/retry.tsx
+++ b/frontend/app/src/components/buttons/retry.tsx
@@ -32,7 +32,8 @@ export const Retry = (props: tRetryProps) => {
isLoading ? "animate-spin" : "",
isLoading || isDisabled ? "!cursor-not-allowed" : ""
)}
- onClick={handleClick}>
+ onClick={handleClick}
+ >
((props:
type="button"
className={classNames(DEFAULT_CLASS(className), customClassName, className)}
onClick={onClick}
- {...propsToPass}>
+ {...propsToPass}
+ >
{props.children}
);
diff --git a/frontend/app/src/components/buttons/select-button.tsx b/frontend/app/src/components/buttons/select-button.tsx
index b98d09094a..8d1dc39d21 100644
--- a/frontend/app/src/components/buttons/select-button.tsx
+++ b/frontend/app/src/components/buttons/select-button.tsx
@@ -21,7 +21,8 @@ export const SelectButton = (props: any) => {
as={Button}
buttonType={BUTTON_TYPES.MAIN}
data-cy="branch-list-display-button"
- data-testid="branch-list-display-button">
+ data-testid="branch-list-display-button"
+ >
{valueLabel}
@@ -35,11 +36,13 @@ export const SelectButton = (props: any) => {
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
- leaveTo="opacity-0">
+ leaveTo="opacity-0"
+ >
+ data-testid="branch-list-dropdown"
+ >
{options.map((option: any) => (
{
"cursor-pointer select-none p-4 text-sm"
)
}
- value={option}>
+ value={option}
+ >
{(attributes) =>
renderOption({
option,
diff --git a/frontend/app/src/components/buttons/tabs-buttons.tsx b/frontend/app/src/components/buttons/tabs-buttons.tsx
index e3447ab444..794bc980be 100644
--- a/frontend/app/src/components/buttons/tabs-buttons.tsx
+++ b/frontend/app/src/components/buttons/tabs-buttons.tsx
@@ -1,7 +1,7 @@
import { QSP } from "@/config/qsp";
+import { ReactNode } from "react";
import { StringParam, useQueryParam } from "use-query-params";
import { Button } from "./button-primitive";
-import { ReactNode } from "react";
type Tab = {
name?: string;
@@ -31,7 +31,8 @@ export const TabsButtons = (props: TabsProps) => {
(qspTab && qspTab === tab.name) || (!qspTab && index === 0) ? "active" : "outline"
}
disabled={tab.disabled}
- className={"border-0 px-4 py-2 rounded-none"}>
+ className={"border-0 px-4 py-2 rounded-none"}
+ >
{tab.label}
))}
diff --git a/frontend/app/src/components/buttons/toggle-buttons.tsx b/frontend/app/src/components/buttons/toggle-buttons.tsx
index 0c7b204dc6..b90094ae26 100644
--- a/frontend/app/src/components/buttons/toggle-buttons.tsx
+++ b/frontend/app/src/components/buttons/toggle-buttons.tsx
@@ -23,7 +23,8 @@ export const ToggleButtons = ({ tabs, ...props }: TabsProps) => {
size={"sm"}
variant={tab.isActive ? "active" : "ghost"}
className={"cursor-pointer border-0 px-4 py-2 rounded-none"}
- {...props}>
+ {...props}
+ >
{tab.label}
))}
diff --git a/frontend/app/src/components/conversations/add-comment.tsx b/frontend/app/src/components/conversations/add-comment.tsx
index f15242bc9d..c25b964185 100644
--- a/frontend/app/src/components/conversations/add-comment.tsx
+++ b/frontend/app/src/components/conversations/add-comment.tsx
@@ -1,11 +1,11 @@
import { Button, LinkButton } from "@/components/buttons/button-primitive";
+import TextareaField from "@/components/form/fields/textarea.field";
+import { isRequired } from "@/components/form/utils/validation";
+import { Form, FormRef, FormSubmit } from "@/components/ui/form";
import { useAuth } from "@/hooks/useAuth";
import { constructPath } from "@/utils/fetch";
import React, { forwardRef, ReactElement } from "react";
import { useLocation } from "react-router-dom";
-import { Form, FormRef, FormSubmit } from "@/components/ui/form";
-import TextareaField from "@/components/form/fields/textarea.field";
-import { isRequired } from "@/components/form/utils/validation";
type CommentFormData = {
comment: string;
@@ -30,7 +30,8 @@ export const AddComment = forwardRef(({ onSubmit, onCancel
comment: comment.value as string,
};
await onSubmit(commentFormData);
- }}>
+ }}
+ >
(({ onSubmit, onCancel
size="sm"
variant="primary"
to={constructPath("/signin")}
- state={{ from: location }}>
+ state={{ from: location }}
+ >
Sign in
{" "}
to be able to add a comment.
diff --git a/frontend/app/src/components/conversations/comment.tsx b/frontend/app/src/components/conversations/comment.tsx
index 8a1898b16d..600fae51d2 100644
--- a/frontend/app/src/components/conversations/comment.tsx
+++ b/frontend/app/src/components/conversations/comment.tsx
@@ -14,7 +14,8 @@ export const Comment: React.FC = ({ author, createdAt, content, cl
return (
+ data-testid="comment"
+ >
diff --git a/frontend/app/src/components/conversations/thread.tsx b/frontend/app/src/components/conversations/thread.tsx
index 56a07c7fde..d03a43b71e 100644
--- a/frontend/app/src/components/conversations/thread.tsx
+++ b/frontend/app/src/components/conversations/thread.tsx
@@ -2,6 +2,7 @@ import { Button } from "@/components/buttons/button";
import { Checkbox } from "@/components/inputs/checkbox";
import ModalConfirm from "@/components/modals/modal-confirm";
import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { Card } from "@/components/ui/card";
import { Tooltip } from "@/components/ui/tooltip";
import { PROPOSED_CHANGES_THREAD_COMMENT_OBJECT } from "@/config/constants";
import graphqlClient from "@/graphql/graphqlClientApollo";
@@ -21,7 +22,6 @@ import { useState } from "react";
import { toast } from "react-toastify";
import { AddComment } from "./add-comment";
import { Comment } from "./comment";
-import { Card } from "@/components/ui/card";
type tThread = {
thread: any;
@@ -177,7 +177,8 @@ export const Thread = (props: tThread) => {
+ data-cy="thread"
+ >
{displayContext && getThreadTitle(thread)}
{sortedComments.map((comment: any, index: number) => (
diff --git a/frontend/app/src/components/display/accordion.tsx b/frontend/app/src/components/display/accordion.tsx
index 5d2d401568..3a402ee152 100644
--- a/frontend/app/src/components/display/accordion.tsx
+++ b/frontend/app/src/components/display/accordion.tsx
@@ -1,6 +1,6 @@
+import { classNames } from "@/utils/common";
import { Icon } from "@iconify-icon/react";
import { CSSProperties, useState } from "react";
-import { classNames } from "@/utils/common";
export type AccordionProps = {
title?: any;
@@ -30,13 +30,15 @@ export default function Accordion({
setIsOpen(!open)}>
+ onClick={() => setIsOpen(!open)}
+ >
+ )}
+ >
{open ? : }
diff --git a/frontend/app/src/components/display/avatar.tsx b/frontend/app/src/components/display/avatar.tsx
index f73c13ca84..6d5c45d61b 100644
--- a/frontend/app/src/components/display/avatar.tsx
+++ b/frontend/app/src/components/display/avatar.tsx
@@ -1,15 +1,13 @@
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { classNames } from "@/utils/common";
-import { cva, type VariantProps } from "class-variance-authority";
+import { type VariantProps, cva } from "class-variance-authority";
-export const initials = (name?: string) =>
+export const initials = (name: string) =>
name
- ? name
- .split(" ")
- .map((word) => word[0])
- .join("")
- .toUpperCase()
- : "-";
+ .split(" ")
+ .map((word) => word[0])
+ .join("")
+ .toUpperCase();
const avatarVariants = cva("rounded-full flex justify-center items-center", {
variants: {
@@ -20,6 +18,7 @@ const avatarVariants = cva("rounded-full flex justify-center items-center", {
size: {
default: "h-12 w-12",
sm: "h-6 w-6 text-xs",
+ md: "h-8 w-8 text-xs",
},
},
defaultVariants: {
@@ -30,12 +29,13 @@ const avatarVariants = cva("rounded-full flex justify-center items-center", {
interface tAvatar extends VariantProps
{
name?: string;
+ text?: string;
className?: string;
isLoading?: boolean;
}
export const Avatar = (props: tAvatar) => {
- const { name, variant, size, className, isLoading, ...otherProps } = props;
+ const { name, text, variant, size, className, isLoading, ...otherProps } = props;
if (isLoading) {
return (
@@ -47,7 +47,9 @@ export const Avatar = (props: tAvatar) => {
return (
- {initials(name)}
+ {name && initials(name)}
+ {text}
+ {!name && !text && "-"}
);
};
diff --git a/frontend/app/src/components/display/badge-circle.tsx b/frontend/app/src/components/display/badge-circle.tsx
index 8ce1d18ef0..18d5392de2 100644
--- a/frontend/app/src/components/display/badge-circle.tsx
+++ b/frontend/app/src/components/display/badge-circle.tsx
@@ -131,7 +131,8 @@ export const BadgeCircle = (props: tBadgeCircleProps) => {
className,
onDelete ? "cursor-pointer" : ""
)}
- onClick={handleClick}>
+ onClick={handleClick}
+ >
{children}
diff --git a/frontend/app/src/components/display/badge.tsx b/frontend/app/src/components/display/badge.tsx
index 918d62b2f9..c08178c66a 100644
--- a/frontend/app/src/components/display/badge.tsx
+++ b/frontend/app/src/components/display/badge.tsx
@@ -118,7 +118,8 @@ export const Badge = ({
onDelete && !disabled ? "cursor-pointer" : ""
)}
onClick={handleClick}
- {...props}>
+ {...props}
+ >
{children}
{onDelete && (
diff --git a/frontend/app/src/components/display/circle.tsx b/frontend/app/src/components/display/circle.tsx
index 143aae4356..97ef41eabb 100644
--- a/frontend/app/src/components/display/circle.tsx
+++ b/frontend/app/src/components/display/circle.tsx
@@ -13,7 +13,8 @@ export const Circle = (props: tCircleProps) => {
);
diff --git a/frontend/app/src/components/display/color-display.tsx b/frontend/app/src/components/display/color-display.tsx
index d5d95aa8b1..8f1d4d703c 100644
--- a/frontend/app/src/components/display/color-display.tsx
+++ b/frontend/app/src/components/display/color-display.tsx
@@ -1,12 +1,30 @@
import { getTextColor } from "@/utils/common";
+import { Tooltip } from "../ui/tooltip";
type tColorDisplay = {
color?: string | null;
value?: string | null;
+ description?: string | null;
};
export const ColorDisplay = (props: tColorDisplay) => {
- const { color, value } = props;
+ const { color, value, description } = props;
+
+ if (description) {
+ return (
+
+
+ {value}
+
+
+ );
+ }
return (
{
style={{
backgroundColor: color || "",
color: color ? getTextColor(color) : "",
- }}>
+ }}
+ >
{value}
);
diff --git a/frontend/app/src/components/display/meta-details-tooltips.tsx b/frontend/app/src/components/display/meta-details-tooltips.tsx
index 19ea5f0c25..2729db33be 100644
--- a/frontend/app/src/components/display/meta-details-tooltips.tsx
+++ b/frontend/app/src/components/display/meta-details-tooltips.tsx
@@ -76,7 +76,8 @@ export default function MetaDetailsTooltip({
variant="ghost"
className="text-gray-500 focus-visible:ring-0"
data-cy="metadata-button"
- data-testid="view-metadata-button">
+ data-testid="view-metadata-button"
+ >
diff --git a/frontend/app/src/components/display/pie-chart.tsx b/frontend/app/src/components/display/pie-chart.tsx
index 154965d81a..650ca6fd97 100644
--- a/frontend/app/src/components/display/pie-chart.tsx
+++ b/frontend/app/src/components/display/pie-chart.tsx
@@ -67,7 +67,8 @@ export const PieChart = (props: tPieChart) => {
startAngle={90}
endAngle={-270}
// label={renderCustomizedLabel}
- labelLine={false}>
+ labelLine={false}
+ >
{data.map((entry, index) => (
|
))}
diff --git a/frontend/app/src/components/display/pill.tsx b/frontend/app/src/components/display/pill.tsx
index 69ba0aceea..e688fda736 100644
--- a/frontend/app/src/components/display/pill.tsx
+++ b/frontend/app/src/components/display/pill.tsx
@@ -1,12 +1,14 @@
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { classNames } from "@/utils/common";
-import { ReactElement } from "react";
+import { Icon } from "@iconify-icon/react";
+import { ReactNode } from "react";
type tPill = {
type?: PILL_TYPES;
className?: string;
- children?: ReactElement | string | ReactElement[] | string[];
+ children?: ReactNode;
isLoading?: boolean;
+ error?: boolean;
};
export enum PILL_TYPES {
@@ -40,13 +42,14 @@ const getClassName = (type?: PILL_TYPES) => {
};
export const Pill = (props: tPill) => {
- const { type, className = "", children, isLoading } = props;
+ const { type, className = "", children, isLoading, error } = props;
const customClassName = getClassName(type);
return (
{isLoading && }
+ {error && }
{!isLoading && children}
);
diff --git a/frontend/app/src/components/display/popover.tsx b/frontend/app/src/components/display/popover.tsx
index cdb38dc401..600ad15b99 100644
--- a/frontend/app/src/components/display/popover.tsx
+++ b/frontend/app/src/components/display/popover.tsx
@@ -75,7 +75,8 @@ const PopOverPanel = forwardRef(
maxHeightClass[maxHeight ?? POPOVER_SIZE.NONE]
)}
style={style}
- static={staticProp}>
+ static={staticProp}
+ >
{({ close }) => (
<>
{title && {title}
}
diff --git a/frontend/app/src/components/display/properties-popover.tsx b/frontend/app/src/components/display/properties-popover.tsx
index 4020f5ad96..2b887d39f4 100644
--- a/frontend/app/src/components/display/properties-popover.tsx
+++ b/frontend/app/src/components/display/properties-popover.tsx
@@ -59,7 +59,8 @@ const PropertiesPopover = ({
disabled={!permission.write.allow}
tooltipEnabled={!permission.write.allow}
tooltipContent={permission.write.message ?? undefined}
- data-testid="properties-edit-button">
+ data-testid="properties-edit-button"
+ >
@@ -77,7 +78,8 @@ const PropertiesPopover = ({
/>
}
open={showMetaEditModal}
- setOpen={setShowMetaEditModal}>
+ setOpen={setShowMetaEditModal}
+ >
setShowMetaEditModal(false)}
onUpdateComplete={() => refetch && refetch()}
diff --git a/frontend/app/src/components/display/question-mark.tsx b/frontend/app/src/components/display/question-mark.tsx
index 71414370d9..e9287731a9 100644
--- a/frontend/app/src/components/display/question-mark.tsx
+++ b/frontend/app/src/components/display/question-mark.tsx
@@ -1,5 +1,5 @@
-import { Tooltip } from "@/components/ui/tooltip";
import { Button } from "@/components/buttons/button-primitive";
+import { Tooltip } from "@/components/ui/tooltip";
import { classNames } from "@/utils/common";
type tQuestionMark = {
@@ -16,7 +16,8 @@ export const QuestionMark = ({ className, message }: tQuestionMark) => {
size="icon"
variant="outline"
className={classNames("h-4 w-4 p-2 text-[10px]", className)}
- data-cy="question-mark">
+ data-cy="question-mark"
+ >
?
diff --git a/frontend/app/src/components/display/slide-over.tsx b/frontend/app/src/components/display/slide-over.tsx
index e9990959cb..8668312447 100644
--- a/frontend/app/src/components/display/slide-over.tsx
+++ b/frontend/app/src/components/display/slide-over.tsx
@@ -1,11 +1,11 @@
-import { Dialog, Transition } from "@headlessui/react";
-import React, { Fragment, useRef, useState } from "react";
-import { Badge } from "@/components/ui/badge";
-import { Icon } from "@iconify-icon/react";
import { ObjectHelpButton } from "@/components/menu/object-help-button";
-import { useAtomValue } from "jotai/index";
+import { Badge } from "@/components/ui/badge";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { IModelSchema } from "@/state/atoms/schema.atom";
+import { Dialog, Transition } from "@headlessui/react";
+import { Icon } from "@iconify-icon/react";
+import { useAtomValue } from "jotai/index";
+import React, { Fragment, useRef, useState } from "react";
import ModalDelete from "../modals/modal-delete";
interface Props {
@@ -51,7 +51,8 @@ export default function SlideOver(props: Props) {
enterTo="opacity-100"
leave="ease-in-out duration-500"
leaveFrom="opacity-100"
- leaveTo="opacity-0">
+ leaveTo="opacity-0"
+ >
+ leaveTo="translate-x-full"
+ >
+ data-testid="side-panel-container"
+ >
{title}
@@ -103,7 +106,7 @@ export default function SlideOver(props: Props) {
type SlideOverTitleProps = {
schema: IModelSchema;
- currentObjectLabel?: string;
+ currentObjectLabel?: string | null;
title?: React.ReactNode;
subtitle?: React.ReactNode;
};
diff --git a/frontend/app/src/components/display/text-display.tsx b/frontend/app/src/components/display/text-display.tsx
index 9a07ce0141..ffc187572f 100644
--- a/frontend/app/src/components/display/text-display.tsx
+++ b/frontend/app/src/components/display/text-display.tsx
@@ -1,6 +1,6 @@
import { classNames } from "@/utils/common";
import { Icon } from "@iconify-icon/react";
-import { forwardRef, HTMLAttributes, useState } from "react";
+import { HTMLAttributes, forwardRef, useState } from "react";
const MAX_TEXT_LENGTH = 200;
diff --git a/frontend/app/src/components/editor/code-editor.tsx b/frontend/app/src/components/editor/code-editor.tsx
index 6368d72869..912d3c47ca 100644
--- a/frontend/app/src/components/editor/code-editor.tsx
+++ b/frontend/app/src/components/editor/code-editor.tsx
@@ -35,7 +35,8 @@ export const CodeEditor = (props: any) => {
diff --git a/frontend/app/src/components/editor/index.tsx b/frontend/app/src/components/editor/index.tsx
index 28175abc0a..e94e3da49d 100644
--- a/frontend/app/src/components/editor/index.tsx
+++ b/frontend/app/src/components/editor/index.tsx
@@ -65,7 +65,8 @@ export const MarkdownEditor: FC
= forwardRef<
focus-within:outline focus-within:outline-custom-blue-600 focus-within:border-custom-blue-600
`,
className
- )}>
+ )}
+ >
void;
diff --git a/frontend/app/src/components/editor/markdown-editor-header.tsx b/frontend/app/src/components/editor/markdown-editor-header.tsx
index bb315e1d75..7fd8e868c5 100644
--- a/frontend/app/src/components/editor/markdown-editor-header.tsx
+++ b/frontend/app/src/components/editor/markdown-editor-header.tsx
@@ -2,7 +2,7 @@ import { Button } from "@/components/buttons/button";
import { UseCodeMirror } from "@/hooks/useCodeMirror";
import { Icon } from "@iconify-icon/react";
import React, { FC } from "react";
-import { boldCommand, EditorCommand, italicCommand, strikethroughCommand } from "./commands";
+import { EditorCommand, boldCommand, italicCommand, strikethroughCommand } from "./commands";
type ToolbarProps = { codeMirror: UseCodeMirror };
@@ -23,7 +23,8 @@ const ToolBar: FC = ({ codeMirror }) => {
className="bg-white border-none p-0 text-xl shadow-none"
type="button"
aria-label={label}
- onMouseDown={handleButtonMouseDown(onClick)}>
+ onMouseDown={handleButtonMouseDown(onClick)}
+ >
))}
diff --git a/frontend/app/src/components/filters/filter-form.tsx b/frontend/app/src/components/filters/filter-form.tsx
new file mode 100644
index 0000000000..6d75d94ca8
--- /dev/null
+++ b/frontend/app/src/components/filters/filter-form.tsx
@@ -0,0 +1,53 @@
+import { Button } from "@/components/buttons/button-primitive";
+import { FilterKindSelector } from "@/components/filters/filter-kind-selector";
+import { getObjectFromFilters } from "@/components/filters/utils/getObjectFromFilters";
+import { DynamicInput } from "@/components/form/dynamic-form";
+import { getFormFieldsFromSchema } from "@/components/form/utils/getFormFieldsFromSchema";
+import { Form, FormProps, FormRef, FormSubmit } from "@/components/ui/form";
+import { Filter } from "@/hooks/useFilters";
+import { IModelSchema } from "@/state/atoms/schema.atom";
+import { classNames, isGeneric } from "@/utils/common";
+import React, { forwardRef } from "react";
+
+export interface FilterFormProps extends FormProps {
+ schema: IModelSchema;
+ filters: Array;
+ onCancel?: () => void;
+}
+
+export const FilterForm = forwardRef(
+ ({ filters, className, schema, onSubmit, onCancel, ...props }, ref) => {
+ const fields = getFormFieldsFromSchema({
+ schema,
+ isFilterForm: true,
+ initialObject: getObjectFromFilters(schema, filters),
+ });
+
+ return (
+
+ );
+ }
+);
diff --git a/frontend/app/src/components/filters/filter-kind-selector.tsx b/frontend/app/src/components/filters/filter-kind-selector.tsx
new file mode 100644
index 0000000000..d7b35d5294
--- /dev/null
+++ b/frontend/app/src/components/filters/filter-kind-selector.tsx
@@ -0,0 +1,97 @@
+import { DEFAULT_FORM_FIELD_VALUE } from "@/components/form/constants";
+import { LabelFormField } from "@/components/form/fields/common";
+import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { Badge } from "@/components/ui/badge";
+import {
+ Combobox,
+ ComboboxContent,
+ ComboboxItem,
+ ComboboxList,
+ ComboboxTrigger,
+} from "@/components/ui/combobox";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
+import useFilters from "@/hooks/useFilters";
+import { iGenericSchema, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
+import { useAtomValue } from "jotai/index";
+import React, { useState } from "react";
+
+export const FilterKindSelector = ({ genericSchema }: { genericSchema: iGenericSchema }) => {
+ const [activeFilters] = useFilters();
+ const availableNodes = useAtomValue(schemaState);
+ const availableProfiles = useAtomValue(profilesAtom);
+ const allAvailableSchemas = [...availableNodes, ...availableProfiles];
+
+ const selectedKindFilter = activeFilters.find((filter) => filter.name == "kind__value");
+ const compatibleSchemas = (genericSchema.used_by ?? [])
+ .map((kindValue) => {
+ if (!allAvailableSchemas) return null;
+
+ return allAvailableSchemas.find((schema) => schema.kind === kindValue);
+ })
+ .filter((schema) => !!schema);
+
+ return (
+ {
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+ const currentFieldValue = field.value;
+ const selectedSchema = allAvailableSchemas.find(
+ (schema) => schema.kind === currentFieldValue?.value
+ );
+
+ return (
+
+
+
+
+
+
+ {selectedSchema && (
+
+ {selectedSchema.label} {selectedSchema.namespace}
+
+ )}
+
+
+
+
+
+ {compatibleSchemas.map((schemaOption) => (
+ {
+ const newSelectedValue =
+ schemaOption.kind === selectedSchema?.kind ? null : schemaOption.kind;
+ field.onChange(
+ updateFormFieldValue(newSelectedValue ?? null, DEFAULT_FORM_FIELD_VALUE)
+ );
+ setIsDropdownOpen(false);
+ }}
+ >
+ {schemaOption.label}{" "}
+ {schemaOption?.namespace}
+
+ ))}
+
+
+
+
+
+
+ );
+ }}
+ />
+ );
+};
diff --git a/frontend/app/src/components/filters/filters.tsx b/frontend/app/src/components/filters/filters.tsx
index c4d8097fc8..03468a4fdd 100644
--- a/frontend/app/src/components/filters/filters.tsx
+++ b/frontend/app/src/components/filters/filters.tsx
@@ -1,16 +1,14 @@
-import { BUTTON_TYPES, Button } from "@/components/buttons/button";
-import { ButtonWithTooltip } from "@/components/buttons/button-with-tooltip";
+import { Button, ButtonWithTooltip } from "@/components/buttons/button-primitive";
import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import { FilterForm } from "@/components/filters/filter-form";
+import { getFiltersFromFormData } from "@/components/filters/utils/getFiltersFromFormData";
+import { FormFieldValue } from "@/components/form/type";
import { SEARCH_FILTERS } from "@/config/constants";
import useFilters from "@/hooks/useFilters";
-import { Icon } from "@iconify-icon/react";
-import { useState } from "react";
-import ObjectForm from "@/components/form/object-form";
import usePagination from "@/hooks/usePagination";
import { IModelSchema } from "@/state/atoms/schema.atom";
-import { getFiltersFromFormData } from "@/components/filters/utils/getFiltersFromFormData";
-import { FormFieldValue } from "@/components/form/type";
-import { getObjectFromFilters } from "@/components/filters/utils/getObjectFromFilters";
+import { Icon } from "@iconify-icon/react";
+import React, { useState } from "react";
type FiltersProps = {
schema: IModelSchema;
@@ -32,8 +30,6 @@ export const Filters = ({ schema }: FiltersProps) => {
setFilters(newFilters);
};
- const handleShowFilters = () => setShowFilters(true);
-
const handleSubmit = (formData: Record) => {
const newFilters = getFiltersFromFormData(formData);
@@ -50,26 +46,23 @@ export const Filters = ({ schema }: FiltersProps) => {
const currentFilters = filters.filter((filter) => !SEARCH_FILTERS.includes(filter.name));
return (
-
-
+ <>
+
+ onClick={() => setShowFilters(true)}
+ >
Filters: {currentFilters.length}
{!!currentFilters.length && (
-
+ >
);
};
diff --git a/frontend/app/src/components/filters/utils/getObjectFromFilters.ts b/frontend/app/src/components/filters/utils/getObjectFromFilters.ts
index 1f4516afb8..88d6cb7219 100644
--- a/frontend/app/src/components/filters/utils/getObjectFromFilters.ts
+++ b/frontend/app/src/components/filters/utils/getObjectFromFilters.ts
@@ -1,60 +1,63 @@
import { Filter } from "@/hooks/useFilters";
+import { IModelSchema } from "@/state/atoms/schema.atom";
import {
AttributeType,
RelationshipManyType,
RelationshipOneType,
RelationshipType,
} from "@/utils/getObjectItemDisplayValue";
-import { IModelSchema } from "@/state/atoms/schema.atom";
export const getObjectFromFilters = (
schema: IModelSchema,
filters: Array
): Record => {
- return filters.reduce((acc, filter) => {
- const [fieldName, fieldKey] = filter.name.split("__");
-
- if (fieldKey === "value") {
- return {
- ...acc,
- [fieldName]: { value: filter.value } satisfies AttributeType,
- };
- }
+ return filters.reduce(
+ (acc, filter) => {
+ const [fieldName, fieldKey] = filter.name.split("__");
- if (fieldKey === "ids") {
- const relationshipSchema = schema.relationships?.find(({ name }) => name === fieldName);
- if (!relationshipSchema) return acc;
-
- if (relationshipSchema.cardinality === "many") {
+ if (fieldKey === "value") {
return {
...acc,
- [fieldName]: {
- edges: filter.value.map(
- (v: string) =>
- ({
- node: {
- id: v,
- display_label: "",
- __typename: relationshipSchema.peer,
- },
- } satisfies RelationshipOneType)
- ),
- } satisfies RelationshipManyType,
+ [fieldName]: { value: filter.value } satisfies AttributeType,
};
}
- if (relationshipSchema.cardinality === "one") {
- return {
- ...acc,
- [fieldName]: {
- node: { id: filter.value[0], display_label: "", __typename: relationshipSchema.peer },
- } satisfies RelationshipOneType,
- };
+ if (fieldKey === "ids") {
+ const relationshipSchema = schema.relationships?.find(({ name }) => name === fieldName);
+ if (!relationshipSchema) return acc;
+
+ if (relationshipSchema.cardinality === "many") {
+ return {
+ ...acc,
+ [fieldName]: {
+ edges: filter.value.map(
+ (v: string) =>
+ ({
+ node: {
+ id: v,
+ display_label: "",
+ __typename: relationshipSchema.peer,
+ },
+ }) satisfies RelationshipOneType
+ ),
+ } satisfies RelationshipManyType,
+ };
+ }
+
+ if (relationshipSchema.cardinality === "one") {
+ return {
+ ...acc,
+ [fieldName]: {
+ node: { id: filter.value[0], display_label: "", __typename: relationshipSchema.peer },
+ } satisfies RelationshipOneType,
+ };
+ }
+
+ return acc;
}
return acc;
- }
-
- return acc;
- }, {} as Record);
+ },
+ {} as Record
+ );
};
diff --git a/frontend/app/src/components/form/branch-create-form.tsx b/frontend/app/src/components/form/branch-create-form.tsx
index 39dee72e4c..ad0a0036e6 100644
--- a/frontend/app/src/components/form/branch-create-form.tsx
+++ b/frontend/app/src/components/form/branch-create-form.tsx
@@ -1,16 +1,16 @@
+import { Button } from "@/components/buttons/button-primitive";
+import CheckboxField from "@/components/form/fields/checkbox.field";
+import InputField from "@/components/form/fields/input.field";
+import { isMinLength, isRequired } from "@/components/form/utils/validation";
+import { Form, FormSubmit } from "@/components/ui/form";
import { QSP } from "@/config/qsp";
import { Branch } from "@/generated/graphql";
import { BRANCH_CREATE } from "@/graphql/mutations/branches/createBranch";
-import { branchesState } from "@/state/atoms/branches.atom";
import { useMutation } from "@/hooks/useQuery";
+import { branchesState } from "@/state/atoms/branches.atom";
import { useAtom } from "jotai";
-import { StringParam, useQueryParam } from "use-query-params";
-import { Form, FormSubmit } from "@/components/ui/form";
-import { Button } from "@/components/buttons/button-primitive";
import React from "react";
-import InputField from "@/components/form/fields/input.field";
-import { isMinLength, isRequired } from "@/components/form/utils/validation";
-import CheckboxField from "@/components/form/fields/checkbox.field";
+import { StringParam, useQueryParam } from "use-query-params";
type BranchFormData = {
name: string;
@@ -56,7 +56,8 @@ const BranchCreateForm = ({ onCancel, onSuccess }: BranchCreateFormProps) => {
sync_with_git: !!data.sync_with_git.value,
};
await handleSubmit(branchData);
- }}>
+ }}
+ >
{
diff --git a/frontend/app/src/components/form/fields/checkbox.field.tsx b/frontend/app/src/components/form/fields/checkbox.field.tsx
index 5d33244d79..dae988a300 100644
--- a/frontend/app/src/components/form/fields/checkbox.field.tsx
+++ b/frontend/app/src/components/form/fields/checkbox.field.tsx
@@ -1,8 +1,8 @@
-import { Checkbox } from "@/components/inputs/checkbox";
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { FormFieldProps, FormAttributeValue } from "@/components/form/type";
import { LabelFormField } from "@/components/form/fields/common";
+import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { Checkbox } from "@/components/inputs/checkbox";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
export interface CheckboxFieldProps extends FormFieldProps {}
diff --git a/frontend/app/src/components/form/fields/color.field.tsx b/frontend/app/src/components/form/fields/color.field.tsx
index 187f8b6ddc..34c87f74a3 100644
--- a/frontend/app/src/components/form/fields/color.field.tsx
+++ b/frontend/app/src/components/form/fields/color.field.tsx
@@ -1,9 +1,9 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { FormFieldProps, FormAttributeValue } from "@/components/form/type";
-import { InputProps } from "@/components/ui/input";
-import { ColorPicker } from "@/components/inputs/color-picker";
import { LabelFormField } from "@/components/form/fields/common";
+import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { ColorPicker } from "@/components/inputs/color-picker";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
+import { InputProps } from "@/components/ui/input";
export interface InputFieldProps
extends FormFieldProps,
diff --git a/frontend/app/src/components/form/fields/common.tsx b/frontend/app/src/components/form/fields/common.tsx
index 8a6aa1508f..de6352c60b 100644
--- a/frontend/app/src/components/form/fields/common.tsx
+++ b/frontend/app/src/components/form/fields/common.tsx
@@ -1,18 +1,18 @@
-import { FormLabel } from "@/components/ui/form";
import { QuestionMark } from "@/components/display/question-mark";
-import { classNames } from "@/utils/common";
-import { LabelProps } from "@/components/ui/label";
-import { Icon } from "@iconify-icon/react";
-import { Badge } from "@/components/ui/badge";
-import React from "react";
import {
AttributeValueFromProfile,
FormFieldValue,
RelationshipValueFormPool,
} from "@/components/form/type";
+import { Badge } from "@/components/ui/badge";
+import { FormLabel } from "@/components/ui/form";
+import { LabelProps } from "@/components/ui/label";
import { Tooltip } from "@/components/ui/tooltip";
-import { Link } from "react-router-dom";
+import { classNames } from "@/utils/common";
import { getObjectDetailsUrl2 } from "@/utils/objects";
+import { Icon } from "@iconify-icon/react";
+import React from "react";
+import { Link } from "react-router-dom";
export const InputUniqueTips = ({ className }: { className: string }) => (
@@ -66,12 +66,14 @@ const ProfileSourceBadge = ({ fieldData }: { fieldData: AttributeValueFromProfil
This value is set by a profile:
+ className="underline inline-flex items-center gap-1"
+ >
{fieldData?.source?.label}
You can override it by typing another value in the input.
- }>
+ }
+ >
{fieldData?.source?.label}
@@ -90,12 +92,14 @@ const PoolSourceBadge = ({ fieldData }: { fieldData: RelationshipValueFormPool }
This value is allocated from the pool:
+ className="underline inline-flex items-center gap-1"
+ >
{fieldData?.source?.label}
You can override it by entering another value manually.
- }>
+ }
+ >
{fieldData?.source?.label}
diff --git a/frontend/app/src/components/form/fields/datetime.field.tsx b/frontend/app/src/components/form/fields/datetime.field.tsx
index 2d1a781e7c..b6b5e5ecba 100644
--- a/frontend/app/src/components/form/fields/datetime.field.tsx
+++ b/frontend/app/src/components/form/fields/datetime.field.tsx
@@ -1,10 +1,10 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { FormFieldProps, FormAttributeValue } from "@/components/form/type";
-import { DatePicker } from "@/components/inputs/date-picker";
-import { ComponentProps } from "react";
import { LabelFormField } from "@/components/form/fields/common";
-import { formatISO } from "date-fns";
+import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { DatePicker } from "@/components/inputs/date-picker";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
+import { formatISO } from "date-fns";
+import { ComponentProps } from "react";
export interface DatetimeFieldProps
extends FormFieldProps,
diff --git a/frontend/app/src/components/form/fields/dropdown.field.tsx b/frontend/app/src/components/form/fields/dropdown.field.tsx
index 04b41a4b68..e2546d9f25 100644
--- a/frontend/app/src/components/form/fields/dropdown.field.tsx
+++ b/frontend/app/src/components/form/fields/dropdown.field.tsx
@@ -1,15 +1,16 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { Select, SelectProps } from "@/components/inputs/select";
-import { DynamicDropdownFieldProps, FormAttributeValue } from "@/components/form/type";
+import { DEFAULT_FORM_FIELD_VALUE } from "@/components/form/constants";
import { LabelFormField } from "@/components/form/fields/common";
+import { DynamicDropdownFieldProps, FormAttributeValue } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { Dropdown, DropdownProps } from "@/components/inputs/dropdown";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
export interface DropdownFieldProps
extends Omit,
- Omit {}
+ Omit {}
const DropdownField = ({
- defaultValue,
+ defaultValue = DEFAULT_FORM_FIELD_VALUE,
description,
items,
label,
@@ -28,7 +29,7 @@ const DropdownField = ({
const fieldData: FormAttributeValue = field.value;
return (
-
+
-
diff --git a/frontend/app/src/components/form/fields/enum.field.tsx b/frontend/app/src/components/form/fields/enum.field.tsx
index 51f08c1109..43f9f15dfb 100644
--- a/frontend/app/src/components/form/fields/enum.field.tsx
+++ b/frontend/app/src/components/form/fields/enum.field.tsx
@@ -1,22 +1,26 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { DynamicEnumFieldProps, FormAttributeValue } from "@/components/form/type";
-import { ComboboxProps } from "@/components/ui/combobox";
import { LabelFormField } from "@/components/form/fields/common";
-import { Select } from "@/components/inputs/select";
+import { DynamicEnumFieldProps, FormAttributeValue } from "@/components/form/type";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
+import React from "react";
+
+import { DEFAULT_FORM_FIELD_VALUE } from "@/components/form/constants";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { Enum, EnumProps } from "@/components/inputs/enum";
export interface EnumFieldProps
extends Omit
,
- Omit {}
+ Omit {}
const EnumField = ({
- defaultValue,
+ defaultValue = DEFAULT_FORM_FIELD_VALUE,
description,
label,
name,
rules,
unique,
items,
+ schema,
+ field: attributeSchema,
...props
}: EnumFieldProps) => {
return (
@@ -29,7 +33,7 @@ const EnumField = ({
const fieldData: FormAttributeValue = field.value;
return (
-
+
-
diff --git a/frontend/app/src/components/form/fields/input.field.tsx b/frontend/app/src/components/form/fields/input.field.tsx
index 2a2fdbaef0..c67d223562 100644
--- a/frontend/app/src/components/form/fields/input.field.tsx
+++ b/frontend/app/src/components/form/fields/input.field.tsx
@@ -1,8 +1,8 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { Input, InputProps } from "@/components/ui/input";
-import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { LabelFormField } from "@/components/form/fields/common";
+import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
+import { Input, InputProps } from "@/components/ui/input";
export interface InputFieldProps
extends FormFieldProps,
diff --git a/frontend/app/src/components/form/fields/json.field.tsx b/frontend/app/src/components/form/fields/json.field.tsx
index d92169af69..15e34c90aa 100644
--- a/frontend/app/src/components/form/fields/json.field.tsx
+++ b/frontend/app/src/components/form/fields/json.field.tsx
@@ -1,8 +1,8 @@
-import { FormFieldProps, FormAttributeValue } from "@/components/form/type";
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
import { JsonEditor } from "@/components/editor/json/json-editor";
import { LabelFormField } from "@/components/form/fields/common";
+import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
const JsonField = ({
defaultValue,
diff --git a/frontend/app/src/components/form/fields/list.field.tsx b/frontend/app/src/components/form/fields/list.field.tsx
index ac8b19cf36..1d083f90ed 100644
--- a/frontend/app/src/components/form/fields/list.field.tsx
+++ b/frontend/app/src/components/form/fields/list.field.tsx
@@ -1,8 +1,8 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { FormFieldProps } from "@/components/form/type";
-import List from "@/components/list";
import { LabelFormField } from "@/components/form/fields/common";
+import { FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import List from "@/components/list";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
const ListField = ({
defaultValue,
diff --git a/frontend/app/src/components/form/fields/number.field.tsx b/frontend/app/src/components/form/fields/number.field.tsx
index b21ddb3b10..688f501821 100644
--- a/frontend/app/src/components/form/fields/number.field.tsx
+++ b/frontend/app/src/components/form/fields/number.field.tsx
@@ -1,13 +1,13 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { Input, InputProps } from "@/components/ui/input";
-import { DynamicNumberFieldProps, FormAttributeValue } from "@/components/form/type";
import { LabelFormField } from "@/components/form/fields/common";
+import { PoolSelector } from "@/components/form/pool-selector";
+import { DynamicNumberFieldProps, FormAttributeValue } from "@/components/form/type";
import {
updateAttributeFieldValue,
updateFormFieldValue,
} from "@/components/form/utils/updateFormFieldValue";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
+import { Input, InputProps } from "@/components/ui/input";
import React from "react";
-import { PoolSelector } from "@/components/form/pool-selector";
export interface NumberFieldProps
extends Omit
,
@@ -65,7 +65,8 @@ const NumberField = ({
if (defaultValue) field.onChange(defaultValue);
}}
value={fieldData}
- pools={pools}>
+ pools={pools}
+ >
{numberInput}
) : (
diff --git a/frontend/app/src/components/form/fields/password-input.field.tsx b/frontend/app/src/components/form/fields/password-input.field.tsx
index 084d7bcb3b..d6a2cbcf8e 100644
--- a/frontend/app/src/components/form/fields/password-input.field.tsx
+++ b/frontend/app/src/components/form/fields/password-input.field.tsx
@@ -1,8 +1,8 @@
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { PasswordInput } from "@/components/ui/password-input";
-import { FormFieldProps, FormAttributeValue } from "@/components/form/type";
import { LabelFormField } from "@/components/form/fields/common";
+import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
+import { PasswordInput } from "@/components/ui/password-input";
const PasswordInputField = ({
defaultValue = { source: null, value: null },
diff --git a/frontend/app/src/components/form/fields/relationship.field.tsx b/frontend/app/src/components/form/fields/relationship.field.tsx
index 50e47b5277..09792dc8e4 100644
--- a/frontend/app/src/components/form/fields/relationship.field.tsx
+++ b/frontend/app/src/components/form/fields/relationship.field.tsx
@@ -1,20 +1,20 @@
-import { ElementRef, forwardRef, useState } from "react";
-import { useAtomValue } from "jotai";
-import { components } from "@/infraops";
-import { store } from "@/state";
-import { genericsState, IModelSchema, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { Select, SelectOption } from "@/components/inputs/select";
+import { LabelFormField } from "@/components/form/fields/common";
import {
DynamicRelationshipFieldProps,
FormFieldProps,
FormRelationshipValue,
} from "@/components/form/type";
-import { LabelFormField } from "@/components/form/fields/common";
import { updateRelationshipFieldValue } from "@/components/form/utils/updateFormFieldValue";
-import useQuery from "@/hooks/useQuery";
+import { Select, SelectOption } from "@/components/inputs/select";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
import { getRelationshipParent } from "@/graphql/queries/objects/getRelationshipParent";
+import useQuery from "@/hooks/useQuery";
+import { components } from "@/infraops";
+import { store } from "@/state";
+import { IModelSchema, genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { ElementRef, forwardRef, useState } from "react";
const getGenericParentRelationship = (kind?: string) => {
if (!kind) return;
diff --git a/frontend/app/src/components/form/fields/textarea.field.tsx b/frontend/app/src/components/form/fields/textarea.field.tsx
index 014cc3cb6c..a4cdad07bd 100644
--- a/frontend/app/src/components/form/fields/textarea.field.tsx
+++ b/frontend/app/src/components/form/fields/textarea.field.tsx
@@ -1,8 +1,8 @@
import { MarkdownEditor } from "@/components/editor";
-import { FormField, FormInput, FormMessage } from "@/components/ui/form";
-import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { LabelFormField } from "@/components/form/fields/common";
+import { FormAttributeValue, FormFieldProps } from "@/components/form/type";
import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { FormField, FormInput, FormMessage } from "@/components/ui/form";
import { classNames } from "@/utils/common";
const TextareaField = ({
@@ -39,7 +39,8 @@ const TextareaField = ({
className={classNames(
"w-full",
error && "border-red-500 focus-within:border-red-500 focus-within:outline-red-500"
- )}>
+ )}
+ >
{
genericSchema: iGenericSchema;
diff --git a/frontend/app/src/components/form/generic-selector.tsx b/frontend/app/src/components/form/generic-selector.tsx
index 7b8e8cbd74..e263977474 100644
--- a/frontend/app/src/components/form/generic-selector.tsx
+++ b/frontend/app/src/components/form/generic-selector.tsx
@@ -1,9 +1,9 @@
-import { Combobox, tComboboxItem } from "@/components/ui/combobox";
-import { useId } from "react";
+import { Combobox, tComboboxItem } from "@/components/ui/combobox-legacy";
import Label from "@/components/ui/label";
-import { useAtomValue } from "jotai/index";
-import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
import { PROFILE_KIND } from "@/config/constants";
+import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
+import { useAtomValue } from "jotai/index";
+import { useId } from "react";
type GenericSelectorProps = {
currentKind: string;
diff --git a/frontend/app/src/components/form/node-form.tsx b/frontend/app/src/components/form/node-form.tsx
index ed8d177980..f3ced15e39 100644
--- a/frontend/app/src/components/form/node-form.tsx
+++ b/frontend/app/src/components/form/node-form.tsx
@@ -1,29 +1,29 @@
+import DynamicForm from "@/components/form/dynamic-form";
+import { ProfileData } from "@/components/form/object-form";
import { DynamicFieldProps, FormFieldValue, NumberPoolData } from "@/components/form/type";
-import { iNodeSchema, IProfileSchema } from "@/state/atoms/schema.atom";
-import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
-import { useAtomValue } from "jotai/index";
-import { currentBranchAtom } from "@/state/atoms/branches.atom";
-import { datetimeAtom } from "@/state/atoms/time.atom";
-import useFilters from "@/hooks/useFilters";
-import { useAuth } from "@/hooks/useAuth";
import { getFormFieldsFromSchema } from "@/components/form/utils/getFormFieldsFromSchema";
+import { getCreateMutationFromFormData } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { ACCOUNT_TOKEN_OBJECT } from "@/config/constants";
+import { CoreNumberPool } from "@/generated/graphql";
import graphqlClient from "@/graphql/graphqlClientApollo";
import { CREATE_ACCOUNT_TOKEN } from "@/graphql/mutations/accounts/createAccountToken";
-import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
-import { getCreateMutationFromFormData } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
import { createObject } from "@/graphql/mutations/objects/createObject";
-import { stringifyWithoutQuotes } from "@/utils/string";
-import { gql } from "@apollo/client";
-import DynamicForm from "@/components/form/dynamic-form";
-import { classNames } from "@/utils/common";
-import { ProfileData } from "@/components/form/object-form";
-import useQuery from "@/hooks/useQuery";
import { GET_FORM_REQUIREMENTS } from "@/graphql/queries/forms/getFormRequirements";
+import { useAuth } from "@/hooks/useAuth";
+import useFilters from "@/hooks/useFilters";
+import useQuery from "@/hooks/useQuery";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { NUMBER_POOL_KIND } from "@/screens/resource-manager/constants";
-import { CoreNumberPool } from "@/generated/graphql";
+import { currentBranchAtom } from "@/state/atoms/branches.atom";
+import { IProfileSchema, iNodeSchema } from "@/state/atoms/schema.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
+import { classNames } from "@/utils/common";
+import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { stringifyWithoutQuotes } from "@/utils/string";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai/index";
+import { toast } from "react-toastify";
export type NodeFormSubmitParams = {
fields: Array;
diff --git a/frontend/app/src/components/form/node-with-profile-form.tsx b/frontend/app/src/components/form/node-with-profile-form.tsx
index 72757371a4..5a5e1115dc 100644
--- a/frontend/app/src/components/form/node-with-profile-form.tsx
+++ b/frontend/app/src/components/form/node-with-profile-form.tsx
@@ -1,7 +1,7 @@
-import { useState } from "react";
-import { ProfilesSelector } from "@/components/form/profiles-selector";
-import { ProfileData } from "@/components/form/object-form";
import { NodeForm, NodeFormProps } from "@/components/form/node-form";
+import { ProfileData } from "@/components/form/object-form";
+import { ProfilesSelector } from "@/components/form/profiles-selector";
+import { useState } from "react";
export const NodeWithProfileForm = ({ schema, profiles, ...props }: NodeFormProps) => {
const [selectedProfiles, setSelectedProfiles] = useState();
diff --git a/frontend/app/src/components/form/object-create-form-trigger.tsx b/frontend/app/src/components/form/object-create-form-trigger.tsx
index 4afab203bb..43d168ce42 100644
--- a/frontend/app/src/components/form/object-create-form-trigger.tsx
+++ b/frontend/app/src/components/form/object-create-form-trigger.tsx
@@ -1,14 +1,14 @@
-import { Icon } from "@iconify-icon/react";
-import { Button, ButtonProps } from "../buttons/button-primitive";
-import { Tooltip } from "../ui/tooltip";
-import { usePermission } from "@/hooks/usePermission";
-import { useState } from "react";
-import { ACCOUNT_OBJECT, ARTIFACT_OBJECT } from "@/config/constants";
-import { IModelSchema } from "@/state/atoms/schema.atom";
-import { isGeneric } from "@/utils/common";
import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
import ObjectForm from "@/components/form/object-form";
+import { ACCOUNT_GENERIC_OBJECT, ARTIFACT_OBJECT } from "@/config/constants";
import graphqlClient from "@/graphql/graphqlClientApollo";
+import { usePermission } from "@/hooks/usePermission";
+import { IModelSchema } from "@/state/atoms/schema.atom";
+import { isGeneric } from "@/utils/common";
+import { Icon } from "@iconify-icon/react";
+import { useState } from "react";
+import { Button, ButtonProps } from "../buttons/button-primitive";
+import { Tooltip } from "../ui/tooltip";
interface ObjectCreateFormTriggerProps extends ButtonProps {
schema: IModelSchema;
@@ -30,8 +30,8 @@ export const ObjectCreateFormTrigger = ({
}
const isAccount: boolean =
- schema.kind === ACCOUNT_OBJECT ||
- (!isGeneric(schema) && !!schema.inherit_from?.includes(ACCOUNT_OBJECT));
+ schema.kind === ACCOUNT_GENERIC_OBJECT ||
+ (!isGeneric(schema) && !!schema.inherit_from?.includes(ACCOUNT_GENERIC_OBJECT));
const isAllowed = isAccount ? permission.isAdmin.allow : permission.write.allow;
const tooltipMessage = isAccount ? permission.isAdmin.message : permission.isAdmin.message;
@@ -44,7 +44,8 @@ export const ObjectCreateFormTrigger = ({
data-testid="create-object-button"
disabled={!isAllowed || isLoading}
onClick={() => setShowCreateDrawer(true)}
- {...props}>
+ {...props}
+ >
Add {schema?.label}
@@ -60,7 +61,8 @@ export const ObjectCreateFormTrigger = ({
/>
}
open={showCreateDrawer}
- setOpen={setShowCreateDrawer}>
+ setOpen={setShowCreateDrawer}
+ >
{
setShowCreateDrawer(false);
diff --git a/frontend/app/src/components/form/object-edit-slide-over-trigger.tsx b/frontend/app/src/components/form/object-edit-slide-over-trigger.tsx
index 313a1fd4b0..22ac8276c4 100644
--- a/frontend/app/src/components/form/object-edit-slide-over-trigger.tsx
+++ b/frontend/app/src/components/form/object-edit-slide-over-trigger.tsx
@@ -32,7 +32,8 @@ const ObjectEditSlideOverTrigger = ({
tooltipEnabled={!permission.write.allow}
tooltipContent={permission.write.message ?? undefined}
data-testid="edit-button"
- {...props}>
+ {...props}
+ >
@@ -46,7 +47,8 @@ const ObjectEditSlideOverTrigger = ({
/>
}
open={isEditDrawerOpen}
- setOpen={setIsEditDrawerOpen}>
+ setOpen={setIsEditDrawerOpen}
+ >
setIsEditDrawerOpen(false)}
onUpdateComplete={onUpdateComplete}
diff --git a/frontend/app/src/components/form/object-form.tsx b/frontend/app/src/components/form/object-form.tsx
index 72ded9f3d3..991ec514be 100644
--- a/frontend/app/src/components/form/object-form.tsx
+++ b/frontend/app/src/components/form/object-form.tsx
@@ -1,14 +1,24 @@
-import NoDataFound from "@/screens/errors/no-data-found";
import { DynamicFormProps } from "@/components/form/dynamic-form";
-import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
-import { useSchema } from "@/hooks/useSchema";
import { GenericObjectForm } from "@/components/form/generic-object-form";
-import { NodeWithProfileForm } from "@/components/form/node-with-profile-form";
import { NodeForm, NodeFormSubmitParams } from "@/components/form/node-form";
-import { NUMBER_POOL_OBJECT, READONLY_REPOSITORY_KIND, REPOSITORY_KIND } from "@/config/constants";
-import { NumberPoolForm } from "@/screens/resource-manager/number-pool-form";
-import { lazy, Suspense } from "react";
+import { NodeWithProfileForm } from "@/components/form/node-with-profile-form";
+import {
+ ACCOUNT_GROUP_OBJECT,
+ ACCOUNT_OBJECT,
+ NUMBER_POOL_OBJECT,
+ OBJECT_PERMISSION_OBJECT,
+ READONLY_REPOSITORY_KIND,
+ REPOSITORY_KIND,
+} from "@/config/constants";
+import { useSchema } from "@/hooks/useSchema";
+import NoDataFound from "@/screens/errors/no-data-found";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import { NumberPoolForm } from "@/screens/resource-manager/number-pool-form";
+import { AccountForm } from "@/screens/role-management/account-form";
+import { AccountGroupForm } from "@/screens/role-management/account-group-form";
+import { ObjectPermissionForm } from "@/screens/role-management/object-permissions-form";
+import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { Suspense, lazy } from "react";
export type ProfileData = {
[key: string]: string | Pick;
@@ -24,13 +34,12 @@ export interface ObjectFormProps extends Omit void;
currentObject?: Record;
currentProfiles?: ProfileData[];
- isFilterForm?: boolean;
isUpdate?: boolean;
onSubmit?: (data: NodeFormSubmitParams) => void;
onUpdateComplete?: () => void;
}
-const ObjectForm = ({ kind, isFilterForm, currentProfiles, ...props }: ObjectFormProps) => {
+const ObjectForm = ({ kind, currentProfiles, ...props }: ObjectFormProps) => {
const { schema, isNode, isGeneric } = useSchema(kind);
if (!schema) {
@@ -41,10 +50,6 @@ const ObjectForm = ({ kind, isFilterForm, currentProfiles, ...props }: ObjectFor
);
}
- if (isFilterForm) {
- return ;
- }
-
if ([REPOSITORY_KIND, READONLY_REPOSITORY_KIND].includes(kind)) {
return (
}>
@@ -57,24 +62,27 @@ const ObjectForm = ({ kind, isFilterForm, currentProfiles, ...props }: ObjectFor
return ;
}
+ if (kind === OBJECT_PERMISSION_OBJECT) {
+ return ;
+ }
+
+ if (kind === ACCOUNT_GROUP_OBJECT) {
+ return ;
+ }
+
+ if (kind === ACCOUNT_OBJECT) {
+ return ;
+ }
+
if (isGeneric) {
return ;
}
if (isNode && schema.generate_profile) {
- return (
-
- );
+ return ;
}
- return (
-
- );
+ return ;
};
export default ObjectForm;
diff --git a/frontend/app/src/components/form/pool-selector.tsx b/frontend/app/src/components/form/pool-selector.tsx
index 401396c7c2..d0ebb8b0b6 100644
--- a/frontend/app/src/components/form/pool-selector.tsx
+++ b/frontend/app/src/components/form/pool-selector.tsx
@@ -1,12 +1,12 @@
-import React, { forwardRef } from "react";
+import { Button } from "@/components/buttons/button-primitive";
import { FormFieldValue, NumberPoolData } from "@/components/form/type";
-import { ComboboxList, tComboboxItem } from "@/components/ui/combobox";
+import { ComboboxList, tComboboxItem } from "@/components/ui/combobox-legacy";
import { Popover, PopoverAnchor, PopoverTrigger } from "@/components/ui/popover";
-import { Slot } from "@radix-ui/react-slot";
-import { Button } from "@/components/buttons/button-primitive";
-import { Icon } from "@iconify-icon/react";
import { Tooltip } from "@/components/ui/tooltip";
import { Combobox as ComboboxPrimitive } from "@headlessui/react";
+import { Icon } from "@iconify-icon/react";
+import { Slot } from "@radix-ui/react-slot";
+import React, { forwardRef } from "react";
export type PoolValue = {
from_pool: {
@@ -54,7 +54,8 @@ export const PoolSelector = forwardRef(
setOverride(true)}
- className="flex gap-2 justify-start w-full border-gray-300 shadow-none h-10 px-2 font-normal">
+ className="flex gap-2 justify-start w-full border-gray-300 shadow-none h-10 px-2 font-normal"
+ >
{value.source.label}
@@ -66,7 +67,8 @@ export const PoolSelector = forwardRef(
+ data-testid="number-pool-button"
+ >
diff --git a/frontend/app/src/components/form/profiles-selector.tsx b/frontend/app/src/components/form/profiles-selector.tsx
index 5129a33e8f..538f1179af 100644
--- a/frontend/app/src/components/form/profiles-selector.tsx
+++ b/frontend/app/src/components/form/profiles-selector.tsx
@@ -1,14 +1,14 @@
-import { genericsState, iNodeSchema, profilesAtom } from "@/state/atoms/schema.atom";
-import { useId } from "react";
-import { useAtomValue } from "jotai/index";
-import { getObjectAttributes } from "@/utils/getSchemaObjectColumns";
-import ErrorScreen from "@/screens/errors/error-screen";
+import { MultiCombobox } from "@/components/ui/combobox-legacy";
+import Label from "@/components/ui/label";
import { getProfiles } from "@/graphql/queries/objects/getProfiles";
-import { gql } from "@apollo/client";
import useQuery from "@/hooks/useQuery";
+import ErrorScreen from "@/screens/errors/error-screen";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
-import Label from "@/components/ui/label";
-import { MultiCombobox } from "@/components/ui/combobox";
+import { genericsState, iNodeSchema, profilesAtom } from "@/state/atoms/schema.atom";
+import { getObjectAttributes } from "@/utils/getSchemaObjectColumns";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai/index";
+import { useId } from "react";
type ProfilesSelectorProps = {
schema: iNodeSchema;
diff --git a/frontend/app/src/components/form/type.ts b/frontend/app/src/components/form/type.ts
index 0ba6a62230..98f619454b 100644
--- a/frontend/app/src/components/form/type.ts
+++ b/frontend/app/src/components/form/type.ts
@@ -1,9 +1,10 @@
+import { DropdownOption } from "@/components/inputs/dropdown";
+import { SelectOption } from "@/components/inputs/select";
import { FormField } from "@/components/ui/form";
import { SchemaAttributeType } from "@/screens/edit-form-hook/dynamic-control-types";
-import { ComponentProps } from "react";
-import { SelectOption } from "@/components/inputs/select";
-import { components } from "@/infraops";
+import { AttributeSchema, RelationshipSchema } from "@/screens/schema/types";
import { IModelSchema } from "@/state/atoms/schema.atom";
+import { ComponentProps } from "react";
type SourceType = "schema" | "user";
@@ -96,19 +97,15 @@ export type DynamicNumberFieldProps = FormFieldProps & {
export type DynamicDropdownFieldProps = FormFieldProps & {
type: "Dropdown";
- items: Array;
- field?:
- | components["schemas"]["AttributeSchema-Output"]
- | components["schemas"]["RelationshipSchema-Output"];
+ items: Array;
+ field?: AttributeSchema;
schema?: IModelSchema;
};
export type DynamicEnumFieldProps = FormFieldProps & {
type: "enum";
- items: Array;
- field?:
- | components["schemas"]["AttributeSchema-Output"]
- | components["schemas"]["RelationshipSchema-Output"];
+ items: Array;
+ field?: AttributeSchema;
schema?: IModelSchema;
};
@@ -118,7 +115,7 @@ export type DynamicRelationshipFieldProps = Omit
peer?: string;
parent?: string;
options?: SelectOption[];
- relationship: components["schemas"]["RelationshipSchema-Output"];
+ relationship: RelationshipSchema;
schema: IModelSchema;
};
diff --git a/frontend/app/src/components/form/utils/getFieldDefaultValue.ts b/frontend/app/src/components/form/utils/getFieldDefaultValue.ts
index 87399efc5b..6a3378668d 100644
--- a/frontend/app/src/components/form/utils/getFieldDefaultValue.ts
+++ b/frontend/app/src/components/form/utils/getFieldDefaultValue.ts
@@ -1,4 +1,3 @@
-import { FieldSchema, AttributeType } from "@/utils/getObjectItemDisplayValue";
import { ProfileData } from "@/components/form/object-form";
import {
AttributeValueFormPool,
@@ -6,8 +5,9 @@ import {
AttributeValueFromUser,
FormAttributeValue,
} from "@/components/form/type";
-import * as R from "ramda";
import { LineageSource } from "@/generated/graphql";
+import { AttributeType, FieldSchema } from "@/utils/getObjectItemDisplayValue";
+import * as R from "ramda";
export type GetFieldDefaultValue = {
fieldSchema: FieldSchema;
diff --git a/frontend/app/src/components/form/utils/getFormFieldsFromSchema.ts b/frontend/app/src/components/form/utils/getFormFieldsFromSchema.ts
index c2b7836ad7..6b002bcefb 100644
--- a/frontend/app/src/components/form/utils/getFormFieldsFromSchema.ts
+++ b/frontend/app/src/components/form/utils/getFormFieldsFromSchema.ts
@@ -1,12 +1,4 @@
-import {
- genericsState,
- iGenericSchema,
- iNodeSchema,
- profilesAtom,
- schemaState,
-} from "@/state/atoms/schema.atom";
-import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
-import { AuthContextType } from "@/hooks/useAuth";
+import { ProfileData } from "@/components/form/object-form";
import {
DynamicDropdownFieldProps,
DynamicEnumFieldProps,
@@ -17,19 +9,20 @@ import {
FormFieldValue,
NumberPoolData,
} from "@/components/form/type";
-import { getOptionsFromAttribute, getRelationshipOptions } from "@/utils/getSchemaObjectColumns";
-import { isGeneric, sortByOrderWeight } from "@/utils/common";
import { getFieldDefaultValue } from "@/components/form/utils/getFieldDefaultValue";
-import { SchemaAttributeType } from "@/screens/edit-form-hook/dynamic-control-types";
-import { store } from "@/state";
-import { SCHEMA_ATTRIBUTE_KIND } from "@/config/constants";
-import { ProfileData } from "@/components/form/object-form";
-import { isFieldDisabled } from "@/components/form/utils/isFieldDisabled";
import { getRelationshipDefaultValue } from "@/components/form/utils/getRelationshipDefaultValue";
-import { Filter } from "@/hooks/useFilters";
import { getRelationshipParent } from "@/components/form/utils/getRelationshipParent";
-import { isRequired } from "@/components/form/utils/validation";
import { getRelationshipsForForm } from "@/components/form/utils/getRelationshipsForForm";
+import { isFieldDisabled } from "@/components/form/utils/isFieldDisabled";
+import { isRequired } from "@/components/form/utils/validation";
+import { SCHEMA_ATTRIBUTE_KIND } from "@/config/constants";
+import { AuthContextType } from "@/hooks/useAuth";
+import { SchemaAttributeType } from "@/screens/edit-form-hook/dynamic-control-types";
+import { store } from "@/state";
+import { genericsState, iGenericSchema, iNodeSchema, schemaState } from "@/state/atoms/schema.atom";
+import { sortByOrderWeight } from "@/utils/common";
+import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { getRelationshipOptions } from "@/utils/getSchemaObjectColumns";
type GetFormFieldsFromSchema = {
schema: iNodeSchema | iGenericSchema;
@@ -37,7 +30,6 @@ type GetFormFieldsFromSchema = {
initialObject?: Record;
auth?: AuthContextType;
isFilterForm?: boolean;
- filters?: Array;
pools?: Array;
isUpdate?: boolean;
};
@@ -48,7 +40,6 @@ export const getFormFieldsFromSchema = ({
initialObject,
auth,
isFilterForm,
- filters,
pools = [],
isUpdate,
}: GetFormFieldsFromSchema): Array => {
@@ -124,8 +115,8 @@ export const getFormFieldsFromSchema = ({
field: attribute,
schema: schema,
items: (attribute.choices ?? []).map((choice) => ({
- id: choice.id ?? choice.name,
- name: choice.label ?? choice.name,
+ value: choice.name,
+ label: choice.label ?? choice.name,
color: choice.color ?? undefined,
description: choice.description ?? undefined,
})),
@@ -141,7 +132,7 @@ export const getFormFieldsFromSchema = ({
field: attribute,
schema: schema,
unique: attribute.unique,
- items: getOptionsFromAttribute(attribute, basicFomFieldProps.defaultValue),
+ items: attribute.enum,
};
return enumField;
@@ -168,40 +159,5 @@ export const getFormFieldsFromSchema = ({
return field;
});
- // Allow kind filter for generic
- if (isFilterForm && isGeneric(schema) && schema.used_by?.length) {
- const kindFilter = filters?.find((filter) => filter.name == "kind__value");
- const nodes = store.get(schemaState);
- const profiles = store.get(profilesAtom);
- const schemas = [...nodes, ...profiles];
-
- const items = schema.used_by
- .map((kind) => {
- if (!schemas) return null;
-
- const relatedSchema = schemas.find((schema) => schema.kind === kind);
-
- if (!relatedSchema) return null;
-
- return {
- id: relatedSchema.kind as string,
- name: relatedSchema.label ?? relatedSchema.name,
- badge: relatedSchema.namespace,
- };
- })
- .filter((n) => n !== null);
-
- const genericKindField: DynamicDropdownFieldProps = {
- name: "kind",
- label: "Kind",
- description: "Select a kind to filter nodes",
- type: "Dropdown",
- defaultValue: kindFilter ? { source: { type: "user" }, value: kindFilter.value } : undefined,
- items,
- };
-
- return [genericKindField, ...formFields];
- }
-
return formFields;
};
diff --git a/frontend/app/src/components/form/utils/getRelationshipDefaultValue.ts b/frontend/app/src/components/form/utils/getRelationshipDefaultValue.ts
index 1b1b217ec9..e0fe0e98f7 100644
--- a/frontend/app/src/components/form/utils/getRelationshipDefaultValue.ts
+++ b/frontend/app/src/components/form/utils/getRelationshipDefaultValue.ts
@@ -1,8 +1,8 @@
import { FormRelationshipValue } from "@/components/form/type";
-import { RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { RESOURCE_GENERIC_KIND } from "@/screens/resource-manager/constants";
import { store } from "@/state";
import { schemaState } from "@/state/atoms/schema.atom";
-import { RESOURCE_GENERIC_KIND } from "@/screens/resource-manager/constants";
+import { RelationshipType } from "@/utils/getObjectItemDisplayValue";
type GetRelationshipDefaultValueParams = {
relationshipData: RelationshipType | undefined;
diff --git a/frontend/app/src/components/form/utils/getRelationshipsForForm.ts b/frontend/app/src/components/form/utils/getRelationshipsForForm.ts
index abacd4cf49..d25750897d 100644
--- a/frontend/app/src/components/form/utils/getRelationshipsForForm.ts
+++ b/frontend/app/src/components/form/utils/getRelationshipsForForm.ts
@@ -1,5 +1,5 @@
-import { components } from "@/infraops";
import { relationshipKindForForm } from "@/config/constants";
+import { components } from "@/infraops";
import { RelationshipKind } from "@/screens/objects/types";
export const getRelationshipsForForm = (
diff --git a/frontend/app/src/components/form/utils/updateFormFieldValue.ts b/frontend/app/src/components/form/utils/updateFormFieldValue.ts
index 59f73c5156..a334618cda 100644
--- a/frontend/app/src/components/form/utils/updateFormFieldValue.ts
+++ b/frontend/app/src/components/form/utils/updateFormFieldValue.ts
@@ -1,3 +1,4 @@
+import { PoolValue } from "@/components/form/pool-selector";
import {
AttributeValueFormPool,
FormAttributeValue,
@@ -6,7 +7,6 @@ import {
RelationshipValueFormPool,
} from "@/components/form/type";
import { isDeepEqual } from "remeda";
-import { PoolValue } from "@/components/form/pool-selector";
export const updateFormFieldValue = (
newValue: Exclude["value"],
diff --git a/frontend/app/src/components/inputs/checkbox.tsx b/frontend/app/src/components/inputs/checkbox.tsx
index 36cd37faab..5883299440 100644
--- a/frontend/app/src/components/inputs/checkbox.tsx
+++ b/frontend/app/src/components/inputs/checkbox.tsx
@@ -1,6 +1,6 @@
import { focusStyle } from "@/components/ui/style";
import { classNames } from "@/utils/common";
-import { forwardRef, InputHTMLAttributes } from "react";
+import { InputHTMLAttributes, forwardRef } from "react";
interface CheckboxProps extends InputHTMLAttributes {}
diff --git a/frontend/app/src/components/inputs/color-picker.tsx b/frontend/app/src/components/inputs/color-picker.tsx
index ce9881ce1b..810994add0 100644
--- a/frontend/app/src/components/inputs/color-picker.tsx
+++ b/frontend/app/src/components/inputs/color-picker.tsx
@@ -39,7 +39,8 @@ export const ColorPicker = forwardRef((props, ref) => {
className={classNames(
"flex items-center relative",
disabled && "pointer-events-none opacity-50"
- )}>
+ )}
+ >
((props, ref) => {
title={"Select a color"}
height={POPOVER_SIZE.NONE}
width={POPOVER_SIZE.NONE}
- className="right- left-0">
+ className="right- left-0"
+ >
{() => (
diff --git a/frontend/app/src/components/inputs/date-picker.tsx b/frontend/app/src/components/inputs/date-picker.tsx
index 5e00c0532f..7f3b0bd973 100644
--- a/frontend/app/src/components/inputs/date-picker.tsx
+++ b/frontend/app/src/components/inputs/date-picker.tsx
@@ -2,9 +2,9 @@ import DateTimePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { Button } from "@/components/buttons/button";
+import { Input } from "@/components/inputs/input";
import { format, isValid } from "date-fns";
import { forwardRef, useEffect, useRef, useState } from "react";
-import { Input } from "@/components/inputs/input";
export const DatePicker = forwardRef((props, ref) => {
const { id, date, onChange, disabled, isProtected } = props;
@@ -67,7 +67,8 @@ export const DatePicker = forwardRef((props, ref) => {
+ disabled={disabled || isProtected || (!currentDate && !text)}
+ >
Reset
diff --git a/frontend/app/src/components/inputs/dropdown.tsx b/frontend/app/src/components/inputs/dropdown.tsx
new file mode 100644
index 0000000000..36245e107c
--- /dev/null
+++ b/frontend/app/src/components/inputs/dropdown.tsx
@@ -0,0 +1,274 @@
+import { Button } from "@/components/buttons/button-primitive";
+import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import DynamicForm from "@/components/form/dynamic-form";
+import { isRequired } from "@/components/form/utils/validation";
+import ModalDelete from "@/components/modals/modal-delete";
+import { Badge } from "@/components/ui/badge";
+import {
+ Combobox,
+ ComboboxContent,
+ ComboboxEmpty,
+ ComboboxItem,
+ ComboboxList,
+ ComboboxTrigger,
+} from "@/components/ui/combobox";
+import { CommandItem } from "@/components/ui/command";
+import {
+ DROPDOWN_ADD_MUTATION,
+ DROPDOWN_REMOVE_MUTATION,
+} from "@/graphql/mutations/schema/dropdown";
+import { useMutation } from "@/hooks/useQuery";
+import { AttributeSchema } from "@/screens/schema/types";
+import { IModelSchema } from "@/state/atoms/schema.atom";
+import { classNames, getTextColor } from "@/utils/common";
+import { Icon } from "@iconify-icon/react";
+import React, { forwardRef, HTMLAttributes, useState } from "react";
+
+export type DropdownOption = {
+ value: string;
+ label: string;
+ color?: string;
+ description?: string;
+};
+
+export interface DropdownProps extends Omit, "onChange"> {
+ value?: DropdownOption["value"] | null;
+ items: Array;
+ className?: string;
+ onChange: (value: DropdownOption["value"] | null) => void;
+ schema?: IModelSchema;
+ field?: AttributeSchema;
+}
+
+export interface DropdownItemProps extends React.ComponentPropsWithoutRef {
+ fieldSchema?: {
+ name: string;
+ };
+ schema?: IModelSchema;
+ onDelete: (item: DropdownOption) => void;
+ item: DropdownOption;
+}
+
+export const DropdownItem = React.forwardRef<
+ React.ElementRef,
+ DropdownItemProps
+>(({ fieldSchema, schema, onDelete, className, item, ...props }, ref) => {
+ const [showDeleteModal, setShowDeleteModal] = useState(false);
+ const [removeDropdownOption, { loading }] = useMutation(DROPDOWN_REMOVE_MUTATION);
+
+ return (
+
+
+
+ {item.label}
+
+
{item.description}
+
+
+ {schema && fieldSchema && (
+ <>
+ {
+ e.stopPropagation();
+ setShowDeleteModal(true);
+ }}
+ >
+
+
+
+
+ Are you sure you want to delete the option{" "}
+
+ {item.label}
+ {" "}
+ ?
+ >
+ }
+ setOpen={setShowDeleteModal}
+ onCancel={() => setShowDeleteModal(false)}
+ onDelete={async () => {
+ try {
+ await removeDropdownOption({
+ variables: {
+ kind: schema.kind,
+ attribute: fieldSchema.name,
+ dropdown: item.value,
+ },
+ });
+ onDelete(item);
+ } catch (error) {
+ console.error("Error deleting dropdown item:", error);
+ }
+ }}
+ open={showDeleteModal}
+ isLoading={loading}
+ />
+ >
+ )}
+
+ );
+});
+
+interface DropdownAddActionProps {
+ schema: IModelSchema;
+ field: AttributeSchema;
+ addOption: (item: DropdownOption) => void;
+}
+
+export const DropdownAddAction: React.FC = ({
+ schema,
+ field,
+ addOption,
+}) => {
+ const [open, setOpen] = useState(false);
+ const [addDropdownItem] = useMutation(DROPDOWN_ADD_MUTATION);
+
+ return (
+
+ setOpen(!open)}
+ >
+ + Add option
+
+
+
+ }
+ open={open}
+ setOpen={setOpen}
+ offset={1}
+ >
+ {
+ const { data } = await addDropdownItem({
+ variables: {
+ kind: schema.kind,
+ attribute: field.name,
+ dropdown: formData.value.value,
+ label: formData.label?.value,
+ color: formData.color?.value,
+ description: formData.description?.value,
+ },
+ });
+ if (data?.SchemaDropdownAdd?.ok) {
+ addOption(data?.SchemaDropdownAdd?.object);
+ setOpen(false);
+ }
+ }}
+ onCancel={() => setOpen(false)}
+ className="p-4"
+ />
+
+
+ );
+};
+
+export const Dropdown = forwardRef(
+ ({ items, onChange, value, schema, field, ...props }, ref) => {
+ const [localItems, setLocalItems] = useState(items);
+ const [open, setOpen] = useState(false);
+
+ const handleAddOption = (newOption: DropdownOption) => {
+ setLocalItems([...localItems, newOption]);
+ onChange(newOption.value);
+ };
+
+ const handleDeleteOption = (deletedItem: DropdownOption) => {
+ setLocalItems(localItems.filter((item) => item.value !== deletedItem.value));
+ if (value === deletedItem.value) {
+ onChange(null);
+ }
+ };
+
+ const selectItem = localItems.find((item) => item.value === value);
+
+ return (
+
+
+ {selectItem?.label}
+
+
+
+
+ No dropdown found.
+ {localItems.map((item) => (
+ {
+ onChange(item.value === value ? null : item.value);
+ setOpen(false);
+ }}
+ item={item}
+ onDelete={handleDeleteOption}
+ />
+ ))}
+
+
+ {schema && field && (
+
+ )}
+
+
+ );
+ }
+);
+
+export function getDropdownStyle(color?: string | null) {
+ if (!color) return undefined;
+
+ return {
+ backgroundColor: color,
+ color: getTextColor(color),
+ };
+}
diff --git a/frontend/app/src/components/inputs/enum.tsx b/frontend/app/src/components/inputs/enum.tsx
new file mode 100644
index 0000000000..88dd284243
--- /dev/null
+++ b/frontend/app/src/components/inputs/enum.tsx
@@ -0,0 +1,214 @@
+import { Button, ButtonProps } from "@/components/buttons/button-primitive";
+import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import DynamicForm from "@/components/form/dynamic-form";
+import { isRequired } from "@/components/form/utils/validation";
+import ModalDelete from "@/components/modals/modal-delete";
+import {
+ Combobox,
+ ComboboxContent,
+ ComboboxEmpty,
+ ComboboxItem,
+ ComboboxList,
+ ComboboxTrigger,
+} from "@/components/ui/combobox";
+import { ENUM_ADD_MUTATION, ENUM_REMOVE_MUTATION } from "@/graphql/mutations/schema/enum";
+import { useMutation } from "@/hooks/useQuery";
+import { AttributeSchema } from "@/screens/schema/types";
+import { IModelSchema } from "@/state/atoms/schema.atom";
+import { Icon } from "@iconify-icon/react";
+import React, { forwardRef, useState } from "react";
+
+export interface EnumDeleteButtonProps extends ButtonProps {
+ fieldSchema: AttributeSchema;
+ schema: IModelSchema;
+ value: string | number;
+ onDelete: (id: string | number) => void;
+}
+
+export const EnumDeleteButton = React.forwardRef(
+ ({ fieldSchema, schema, onDelete, className, value, children, ...props }, ref) => {
+ const [showDeleteModal, setShowDeleteModal] = useState(false);
+ const [removeEnum, { loading }] = useMutation(ENUM_REMOVE_MUTATION, {
+ variables: { kind: schema?.kind, attribute: fieldSchema?.name, enum: value },
+ });
+
+ const handleDelete = async () => {
+ try {
+ await removeEnum();
+ onDelete(value);
+ } catch (error) {
+ console.error("Error deleting enum:", error);
+ }
+ };
+
+ return (
+ <>
+ {
+ e.stopPropagation();
+ setShowDeleteModal(true);
+ }}
+ {...props}
+ >
+
+
+
+
+ Are you sure you want to delete the enum{" "}
+ {value}?
+ >
+ }
+ setOpen={setShowDeleteModal}
+ onCancel={() => setShowDeleteModal(false)}
+ onDelete={handleDelete}
+ open={showDeleteModal}
+ isLoading={loading}
+ />
+ >
+ );
+ }
+);
+
+interface EnumAddActionProps {
+ schema?: IModelSchema;
+ field?: AttributeSchema;
+ addOption: (item: string | number) => void;
+}
+
+export const EnumAddAction: React.FC = ({ schema, field, addOption }) => {
+ const [open, setOpen] = useState(false);
+ const [addEnum] = useMutation(ENUM_ADD_MUTATION);
+
+ if (!schema || !field) return null;
+
+ return (
+
+ setOpen(!open)}
+ >
+ + Add option
+
+
+
+ }
+ open={open}
+ setOpen={setOpen}
+ offset={1}
+ >
+ {
+ const newEnumValue = formData.enum.value;
+ const { data } = await addEnum({
+ variables: {
+ kind: schema.kind,
+ attribute: field.name,
+ enum: newEnumValue,
+ },
+ });
+ if (data?.SchemaEnumAdd?.ok) {
+ addOption(newEnumValue as string | number);
+ setOpen(false);
+ }
+ }}
+ onCancel={() => setOpen(false)}
+ className="p-4"
+ />
+
+
+ );
+};
+
+export interface EnumProps {
+ items: Array;
+ value: string | number | null;
+ fieldSchema?: AttributeSchema;
+ schema?: IModelSchema;
+ className?: string;
+ onChange: (value: string | number | null) => void;
+}
+
+export const Enum = forwardRef(
+ ({ items, value, fieldSchema, schema, onChange, ...props }, ref) => {
+ const [localItems, setLocalItems] = useState(items);
+ const [open, setOpen] = useState(false);
+
+ const handleAddOption = (newOption: string | number) => {
+ setLocalItems([...localItems, newOption]);
+ onChange(newOption);
+ };
+
+ const handleDeleteOption = (deletedItem: string | number) => {
+ setLocalItems(localItems.filter((item) => item !== deletedItem));
+ if (value === deletedItem) {
+ onChange(null);
+ }
+ };
+
+ return (
+
+
+ {value}
+
+
+
+
+ No enum found.
+ {localItems.map((item) => (
+ {
+ onChange(item === value ? null : item);
+ setOpen(false);
+ }}
+ {...props}
+ >
+ {item}
+ {schema && fieldSchema && (
+
+ )}
+
+ ))}
+
+
+
+
+
+ );
+ }
+);
diff --git a/frontend/app/src/components/inputs/input.tsx b/frontend/app/src/components/inputs/input.tsx
index faa553ba74..c9b7134d37 100644
--- a/frontend/app/src/components/inputs/input.tsx
+++ b/frontend/app/src/components/inputs/input.tsx
@@ -36,7 +36,8 @@ export const Input = forwardRef((props: any, ref: any) => {
onChange(type === "number" ? 0 : "", event)}>
+ onClick={(event) => onChange(type === "number" ? 0 : "", event)}
+ >
);
@@ -64,7 +65,8 @@ export const Input = forwardRef((props: any, ref: any) => {
className={classNames(
"absolute top-0 bottom-0 flex items-center",
type === "number" ? "right-4" : "right-1"
- )}>
+ )}
+ >
{removeButton}
)}
@@ -72,7 +74,8 @@ export const Input = forwardRef((props: any, ref: any) => {
{error?.message && (
+ data-cy="field-error-message"
+ >
{error?.message}
)}
diff --git a/frontend/app/src/components/inputs/multiple-input.tsx b/frontend/app/src/components/inputs/multiple-input.tsx
index 698ee14f6d..71cc6b220e 100644
--- a/frontend/app/src/components/inputs/multiple-input.tsx
+++ b/frontend/app/src/components/inputs/multiple-input.tsx
@@ -46,14 +46,16 @@ export const MultipleInput = React.forwardRef((props: MultipleInputProps, ref: a
disabled ? "cursor-not-allowed bg-gray-100" : "",
error && error?.message ? "ring-red-500 focus:ring-red-600" : ""
)}
- data-testid="multi-select-input">
+ data-testid="multi-select-input"
+ >
Empty list
{error?.message && (
+ data-cy="field-error-message"
+ >
{error?.message}
)}
@@ -72,7 +74,8 @@ export const MultipleInput = React.forwardRef((props: MultipleInputProps, ref: a
className ?? "",
disabled ? "cursor-not-allowed bg-gray-100" : ""
)}
- data-testid="multi-select-input">
+ data-testid="multi-select-input"
+ >
{value?.map((item: string | SelectOption, index: number) => (
+ disabled={disabled}
+ >
{typeof item === "object" ? item.name : item}
))}
diff --git a/frontend/app/src/components/inputs/select.tsx b/frontend/app/src/components/inputs/select.tsx
index 0b44152b42..272a0813ed 100644
--- a/frontend/app/src/components/inputs/select.tsx
+++ b/frontend/app/src/components/inputs/select.tsx
@@ -1,5 +1,6 @@
import { BUTTON_TYPES, Button } from "@/components/buttons/button";
import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import ObjectForm from "@/components/form/object-form";
import ModalDelete from "@/components/modals/modal-delete";
import {
SCHEMA_DROPDOWN_ADD,
@@ -13,7 +14,6 @@ import { basicMutation } from "@/graphql/mutations/objects/basicMutation";
import { getDropdownOptions } from "@/graphql/queries/objects/dropdownOptions";
import { useLazyQuery } from "@/hooks/useQuery";
import { FormFieldError } from "@/screens/edit-form-hook/form";
-import ObjectForm from "@/components/form/object-form";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { namespacesState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
import { schemaKindNameState } from "@/state/atoms/schemaKindName.atom";
@@ -28,15 +28,15 @@ import { forwardRef, useContext, useEffect, useState } from "react";
import { Input } from "./input";
import { MultipleInput } from "./multiple-input";
+import DynamicForm from "@/components/form/dynamic-form";
import { Tooltip } from "@/components/ui/tooltip";
import { getObjectDisplayLabel } from "@/graphql/queries/objects/getObjectDisplayLabel";
+import usePrevious from "@/hooks/usePrevious";
import { POOLS_DICTIONNARY, POOLS_PEER } from "@/screens/ipam/constants";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { comparedOptions } from "@/utils/array";
import { getOptionsFromRelationship } from "@/utils/getSchemaObjectColumns";
-import DynamicForm from "@/components/form/dynamic-form";
import { Badge } from "../ui/badge";
-import usePrevious from "@/hooks/usePrevious";
export type Parent = {
name?: string;
@@ -613,7 +613,8 @@ export const Select = forwardRef((props, ref) => {
"relative cursor-pointer select-none py-2 pl-3 pr-9 m-2 rounded-md",
active ? "bg-custom-blue-600 text-custom-white" : "bg-gray-100 text-gray-900"
)
- }>
+ }
+ >
Add {schemaKindName[peer]}
@@ -629,7 +630,8 @@ export const Select = forwardRef((props, ref) => {
value={addOption}
className={
"flex relative select-none py-2 pl-3 pr-9 m-2 rounded-md bg-gray-100 text-gray-900 cursor-not-allowed"
- }>
+ }
+ >
Add option
@@ -647,7 +649,8 @@ export const Select = forwardRef((props, ref) => {
"flex relative cursor-pointer select-none py-2 pl-3 pr-9 m-2 rounded-md",
active ? "bg-custom-blue-600 text-custom-white" : "bg-gray-100 text-gray-900"
)
- }>
+ }
+ >
Add option
@@ -674,7 +677,8 @@ export const Select = forwardRef((props, ref) => {
}
open={open}
setOpen={setOpen}
- offset={1}>
+ offset={1}
+ >
((props, ref) => {
}
open={open}
setOpen={setOpen}
- offset={1}>
+ offset={1}
+ >
{renderContentForDropdown()}
@@ -734,7 +739,8 @@ export const Select = forwardRef((props, ref) => {
}
open={open}
setOpen={setOpen}
- offset={1}>
+ offset={1}
+ >
{renderContentForEnum()}
@@ -867,15 +873,17 @@ export const Select = forwardRef((props, ref) => {
return (
+ data-testid="select-container"
+ >
+ {...otherProps}
+ >
((props, ref) => {
canRequestPools ? "right-10" : "right-0"
)}
data-testid="select-open-option-button"
- onClick={handleFocus}>
+ onClick={handleFocus}
+ >
{loading && }
{!loading && (
@@ -911,7 +920,8 @@ export const Select = forwardRef((props, ref) => {
+ onClick={handleFocusPools}
+ >
@@ -923,18 +933,21 @@ export const Select = forwardRef((props, ref) => {
className={classNames(
"absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-custom-white text-base shadow-lg ring-1 ring-custom-black ring-opacity-5 focus:outline-none sm:text-sm",
direction === SelectDirection.OVER ? "bottom-0" : ""
- )}>
+ )}
+ >
{finalOptions.map((option, index) => (
+ style={getOptionStyle(option)}
+ >
{({ selected }) => (
+ className={classNames("block truncate", selected ? "font-semibold" : "")}
+ >
{option.name}
@@ -943,7 +956,8 @@ export const Select = forwardRef
((props, ref) => {
className={classNames(
"block truncate italic text-xs",
selected ? "font-semibold" : ""
- )}>
+ )}
+ >
{option.description}
)}
@@ -962,12 +976,14 @@ export const Select = forwardRef((props, ref) => {
{canRemoveOption(option.id) && (
+ enabled={field.inherited}
+ >
setOptionToDelete(option.id)}>
+ onClick={() => setOptionToDelete(option.id)}
+ >
{}
diff --git a/frontend/app/src/components/menu/object-help-button.tsx b/frontend/app/src/components/menu/object-help-button.tsx
index 95e3568db0..30c7be804f 100644
--- a/frontend/app/src/components/menu/object-help-button.tsx
+++ b/frontend/app/src/components/menu/object-help-button.tsx
@@ -33,7 +33,7 @@ export const ObjectHelpButton = ({ documentationUrl, kind, ...props }: ObjectHel
-
+
Documentation
@@ -41,9 +41,7 @@ export const ObjectHelpButton = ({ documentationUrl, kind, ...props }: ObjectHel
-
+
Schema
diff --git a/frontend/app/src/components/modals/modal-confirm.tsx b/frontend/app/src/components/modals/modal-confirm.tsx
index fcee449c14..52318e0d0f 100644
--- a/frontend/app/src/components/modals/modal-confirm.tsx
+++ b/frontend/app/src/components/modals/modal-confirm.tsx
@@ -40,7 +40,8 @@ export default function ModalConfirm({
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
- leaveTo="opacity-0">
+ leaveTo="opacity-0"
+ >
@@ -53,14 +54,16 @@ export default function ModalConfirm({
enterTo="opacity-100 translate-y-0 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 scale-100"
- leaveTo="opacity-0 translate-y-4 translate-y-0 scale-95">
+ leaveTo="opacity-0 translate-y-4 translate-y-0 scale-95"
+ >
+ className="flex items-center font-semibold leading-6 text-gray-900"
+ >
@@ -75,12 +78,14 @@ export default function ModalConfirm({
+ data-cy="modal-confirm-buttons"
+ >
+ isLoading={isLoading}
+ >
Confirm
{!hideCancel && (
diff --git a/frontend/app/src/components/modals/modal-delete-object.tsx b/frontend/app/src/components/modals/modal-delete-object.tsx
index 67b14c8610..27302e1a1e 100644
--- a/frontend/app/src/components/modals/modal-delete-object.tsx
+++ b/frontend/app/src/components/modals/modal-delete-object.tsx
@@ -1,16 +1,16 @@
-import React, { Fragment, useState } from "react";
-import ModalDelete from "./modal-delete";
-import { deleteObject } from "@/graphql/mutations/objects/deleteObject";
-import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "../ui/alert";
-import graphqlClient from "@/graphql/graphqlClientApollo";
import { ACCOUNT_TOKEN_OBJECT } from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { deleteObject } from "@/graphql/mutations/objects/deleteObject";
+import { currentBranchAtom } from "@/state/atoms/branches.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
import { stringifyWithoutQuotes } from "@/utils/string";
import { gql } from "@apollo/client";
import { useAtomValue } from "jotai";
-import { currentBranchAtom } from "@/state/atoms/branches.atom";
-import { datetimeAtom } from "@/state/atoms/time.atom";
+import React, { Fragment, useState } from "react";
import { useParams } from "react-router-dom";
+import { toast } from "react-toastify";
+import { ALERT_TYPES, Alert } from "../ui/alert";
+import ModalDelete from "./modal-delete";
interface iProps {
label?: string | null;
diff --git a/frontend/app/src/components/modals/modal-delete.tsx b/frontend/app/src/components/modals/modal-delete.tsx
index 3baee92424..39b579900d 100644
--- a/frontend/app/src/components/modals/modal-delete.tsx
+++ b/frontend/app/src/components/modals/modal-delete.tsx
@@ -38,7 +38,8 @@ export default function ModalDelete({
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
- leaveTo="opacity-0">
+ leaveTo="opacity-0"
+ >
@@ -51,17 +52,20 @@ export default function ModalDelete({
enterTo="opacity-100 translate-y-0 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 scale-100"
- leaveTo="opacity-0 translate-y-4 translate-y-0 scale-95">
+ leaveTo="opacity-0 translate-y-4 translate-y-0 scale-95"
+ >
+ data-testid="modal-delete"
+ >
+ className="flex items-center font-semibold leading-6 text-gray-900"
+ >
+ data-testid="modal-delete-confirm"
+ >
{confirmLabel ?? "Delete"}
diff --git a/frontend/app/src/components/modals/modal-success.tsx b/frontend/app/src/components/modals/modal-success.tsx
index d257bce594..de15a449fc 100644
--- a/frontend/app/src/components/modals/modal-success.tsx
+++ b/frontend/app/src/components/modals/modal-success.tsx
@@ -36,7 +36,8 @@ export default function ModalSuccess({
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
- leaveTo="opacity-0">
+ leaveTo="opacity-0"
+ >
@@ -49,14 +50,16 @@ export default function ModalSuccess({
enterTo="opacity-100 translate-y-0 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 scale-100"
- leaveTo="opacity-0 translate-y-4 translate-y-0 scale-95">
+ leaveTo="opacity-0 translate-y-4 translate-y-0 scale-95"
+ >
+ className="flex items-center font-semibold leading-6 text-gray-900"
+ >
@@ -71,12 +74,14 @@ export default function ModalSuccess({
+ data-cy="modal-confirm-buttons"
+ >
+ isLoading={isLoading}
+ >
Confirm
diff --git a/frontend/app/src/components/modals/modal.tsx b/frontend/app/src/components/modals/modal.tsx
index 045853fe03..e86c6fd715 100644
--- a/frontend/app/src/components/modals/modal.tsx
+++ b/frontend/app/src/components/modals/modal.tsx
@@ -23,7 +23,8 @@ export default function Modal(props: Props) {
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
- leaveTo="opacity-0">
+ leaveTo="opacity-0"
+ >
@@ -36,11 +37,13 @@ export default function Modal(props: Props) {
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
- leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
+ leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
+ >
+ className="text-base font-semibold leading-6 text-gray-900 flex items-center px-6"
+ >
Account
Label
@@ -51,14 +54,16 @@ export default function Modal(props: Props) {
setOpen(false)}>
+ onClick={() => setOpen(false)}
+ >
Save
setOpen(false)}
- ref={cancelButtonRef}>
+ ref={cancelButtonRef}
+ >
Cancel
diff --git a/frontend/app/src/components/search/search-actions.tsx b/frontend/app/src/components/search/search-actions.tsx
index 702318dbea..1af7c34b46 100644
--- a/frontend/app/src/components/search/search-actions.tsx
+++ b/frontend/app/src/components/search/search-actions.tsx
@@ -1,6 +1,6 @@
import { Badge } from "@/components/ui/badge";
import { MenuItem } from "@/screens/layout/sidebar/desktop-menu";
-import { genericsState, IModelSchema, menuFlatAtom, schemaState } from "@/state/atoms/schema.atom";
+import { IModelSchema, genericsState, menuFlatAtom, schemaState } from "@/state/atoms/schema.atom";
import { constructPath } from "@/utils/fetch";
import { Icon } from "@iconify-icon/react";
import { useAtomValue } from "jotai";
diff --git a/frontend/app/src/components/search/search-anywhere.tsx b/frontend/app/src/components/search/search-anywhere.tsx
index 9743a1ecb6..56e45f8820 100644
--- a/frontend/app/src/components/search/search-anywhere.tsx
+++ b/frontend/app/src/components/search/search-anywhere.tsx
@@ -1,50 +1,34 @@
+import { Button, ButtonProps } from "@/components/buttons/button-primitive";
+import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import Kbd from "@/components/ui/kbd";
import { classNames } from "@/utils/common";
import { Combobox, Dialog, Transition } from "@headlessui/react";
import { Icon } from "@iconify-icon/react";
-import {
- ChangeEventHandler,
- Fragment,
- MouseEventHandler,
- ReactNode,
- forwardRef,
- useEffect,
- useState,
-} from "react";
+import { Fragment, ReactNode, forwardRef, useEffect, useState } from "react";
import { Link, LinkProps, useNavigate } from "react-router-dom";
import { SearchActions } from "./search-actions";
import { SearchDocs } from "./search-docs";
import { SearchNodes } from "./search-nodes";
-import { Card } from "@/components/ui/card";
-
-type SearchInputProps = {
- className?: string;
- value?: string;
- onChange?: ChangeEventHandler
;
- onClick?: MouseEventHandler;
-};
-const SearchTrigger = ({ value, onChange, onClick, className = "" }: SearchInputProps) => {
+const SearchAnywhereTriggerButton = ({ className, ...props }: ButtonProps) => {
return (
-
-
-
-
-
-
+
+
K
+
);
};
@@ -75,14 +59,7 @@ export function SearchAnywhere({ className = "" }: SearchModalProps) {
return (
<>
-
-
-
+
@@ -130,7 +109,8 @@ const SearchAnywhereDialog = forwardRef(
+ data-testid="search-anywhere"
+ >
{
if (url.length === 0) return;
@@ -142,7 +122,8 @@ const SearchAnywhereDialog = forwardRef(
}
onSelection(url);
- }}>
+ }}
+ >
@@ -183,7 +164,8 @@ export const SearchGroupTitle = ({ children }: SearchGroupProps) => {
+ className="text-xs mb-0.5 pl-1.5 font-semibold text-neutral-600 flex items-center"
+ >
{children}
);
@@ -201,7 +183,8 @@ export const SearchResultItem = ({ className = "", children, to, ...props }: Lin
`flex items-center gap-1 text-xs p-2 rounded ${active ? "bg-gray-100" : ""}`,
className
)
- }>
+ }
+ >
{children}
);
diff --git a/frontend/app/src/components/search/search-nodes.tsx b/frontend/app/src/components/search/search-nodes.tsx
index 85bc8244dd..9bebaa0374 100644
--- a/frontend/app/src/components/search/search-nodes.tsx
+++ b/frontend/app/src/components/search/search-nodes.tsx
@@ -1,18 +1,18 @@
import { Skeleton } from "@/components/skeleton";
+import { Badge } from "@/components/ui/badge";
import { SCHEMA_ATTRIBUTE_KIND, SEARCH_QUERY_NAME } from "@/config/constants";
import { SEARCH } from "@/graphql/queries/objects/search";
import { useDebounce } from "@/hooks/useDebounce";
+import { useObjectDetails } from "@/hooks/useObjectDetails";
import { useLazyQuery } from "@/hooks/useQuery";
+import { useSchema } from "@/hooks/useSchema";
import { constructPath } from "@/utils/fetch";
+import { getSchemaObjectColumns } from "@/utils/getSchemaObjectColumns";
import { getObjectDetailsUrl } from "@/utils/objects";
import { Icon } from "@iconify-icon/react";
import { format } from "date-fns";
import { ReactElement, useEffect } from "react";
import { SearchGroup, SearchGroupTitle, SearchResultItem } from "./search-anywhere";
-import { useObjectDetails } from "@/hooks/useObjectDetails";
-import { useSchema } from "@/hooks/useSchema";
-import { getSchemaObjectColumns } from "@/utils/getSchemaObjectColumns";
-import { Badge } from "@/components/ui/badge";
type SearchProps = {
query: string;
@@ -147,7 +147,8 @@ const NodeAttribute = ({ title, kind, value }: NodeAttributeProps) => {
return (
+ style={{ background: `${color}40` }}
+ >
{value.label}
);
diff --git a/frontend/app/src/components/stats/multiple-progress-bar.tsx b/frontend/app/src/components/stats/multiple-progress-bar.tsx
index ca307df18b..647f07d779 100644
--- a/frontend/app/src/components/stats/multiple-progress-bar.tsx
+++ b/frontend/app/src/components/stats/multiple-progress-bar.tsx
@@ -21,7 +21,8 @@ const MultipleProgressBar = ({ elements, className, ...props }: MultipleProgress
"h-2 w-full overflow-hidden rounded-full bg-custom-blue-600/10 flex",
className
)}
- {...props}>
+ {...props}
+ >
{elements.map(({ className, color, style, tooltip, value, ...props }, index) => {
return (
diff --git a/frontend/app/src/components/stats/pie-chart.tsx b/frontend/app/src/components/stats/pie-chart.tsx
index 3525368742..4747f4062a 100644
--- a/frontend/app/src/components/stats/pie-chart.tsx
+++ b/frontend/app/src/components/stats/pie-chart.tsx
@@ -1,11 +1,11 @@
+import React from "react";
import {
+ Tooltip as ChartTooltip,
Legend,
Pie,
PieChart as PieChartPrimitive,
ResponsiveContainer,
- Tooltip as ChartTooltip,
} from "recharts";
-import React from "react";
type PieChartProps = {
data: Array<{ name: string; value: number }>;
diff --git a/frontend/app/src/components/stats/progress-bar-chart.tsx b/frontend/app/src/components/stats/progress-bar-chart.tsx
index 9db6a871ac..56b39311de 100644
--- a/frontend/app/src/components/stats/progress-bar-chart.tsx
+++ b/frontend/app/src/components/stats/progress-bar-chart.tsx
@@ -8,7 +8,8 @@ export const ProgressBar = ({ className, value, ...props }: ProgressPrimitive.Pr
"relative h-2 w-full overflow-hidden rounded-full bg-custom-blue-600/20",
className
)}
- {...props}>
+ {...props}
+ >
+ {...props}
+ >
{properties.map((property, index) => {
return (
diff --git a/frontend/app/src/components/table/table.tsx b/frontend/app/src/components/table/table.tsx
index a3f6c64cff..48ad21b21e 100644
--- a/frontend/app/src/components/table/table.tsx
+++ b/frontend/app/src/components/table/table.tsx
@@ -15,7 +15,7 @@ export type tRow = {
values: any;
};
-type tTableProps = {
+type TableProps = {
columns: tColumn[];
rows: tRow[];
constructLink?: Function;
@@ -24,9 +24,7 @@ type tTableProps = {
className?: string;
};
-export const Table = (props: tTableProps) => {
- const { columns, rows, onDelete, onUpdate, className } = props;
-
+export const Table = ({ columns, rows, onDelete, onUpdate, className }: TableProps) => {
const auth = useAuth();
return (
@@ -35,7 +33,8 @@ export const Table = (props: tTableProps) => {
className={classNames(
"table-auto border-spacing-0 w-full border border-gray-300 rounded-md",
className
- )}>
+ )}
+ >
{columns.map((column) => (
@@ -55,13 +54,15 @@ export const Table = (props: tTableProps) => {
"border-b border-gray-200 h-[36px]",
row.link ? "hover:bg-gray-50 cursor-pointer" : ""
)}
- data-cy="object-table-row">
+ data-cy="object-table-row"
+ >
{columns.map((column, index) => (
{row.link && (
+ to={row.link}
+ >
{row.values[column.name] ?? "-"}
)}
@@ -82,7 +83,8 @@ export const Table = (props: tTableProps) => {
size="icon"
disabled={!auth?.permissions?.write}
onClick={() => onUpdate(row)}
- data-testid="update-row-button">
+ data-testid="update-row-button"
+ >
)}
@@ -93,8 +95,9 @@ export const Table = (props: tTableProps) => {
size="icon"
disabled={!auth?.permissions?.write}
onClick={() => onDelete(row)}
- data-testid="delete-row-button">
-
+ data-testid="delete-row-button"
+ >
+
)}
|
diff --git a/frontend/app/src/components/tabs-routes.tsx b/frontend/app/src/components/tabs-routes.tsx
new file mode 100644
index 0000000000..d405f0d643
--- /dev/null
+++ b/frontend/app/src/components/tabs-routes.tsx
@@ -0,0 +1,66 @@
+import { Pill } from "@/components/display/pill";
+import { classNames } from "@/utils/common";
+import { ReactNode } from "react";
+import { Link, useMatch } from "react-router-dom";
+
+type TabProps = {
+ to: string;
+ label: ReactNode;
+ count?: number;
+ component?: Function | null;
+ isLoading?: boolean;
+ error?: boolean;
+};
+
+function Tab({ to, label, isLoading, error, count }: TabProps) {
+ const match = useMatch(to);
+
+ return (
+
+ {label}
+
+
+ {count}
+
+
+ );
+}
+
+type TabsProps = {
+ tabs: TabProps[];
+ rightItems?: any;
+ qsp?: string;
+ className?: string;
+};
+
+export function Tabs(props: TabsProps) {
+ const { tabs, rightItems, className } = props;
+
+ return (
+
+
+
+
+
+
+
{rightItems}
+
+ );
+}
diff --git a/frontend/app/src/components/tabs.tsx b/frontend/app/src/components/tabs.tsx
index 5b7fa7fcd7..35ee8bad05 100644
--- a/frontend/app/src/components/tabs.tsx
+++ b/frontend/app/src/components/tabs.tsx
@@ -15,10 +15,11 @@ type TabsProps = {
tabs: Tab[];
rightItems?: any;
qsp?: string;
+ className?: string;
};
export const Tabs = (props: TabsProps) => {
- const { qsp, tabs, rightItems } = props;
+ const { qsp, tabs, rightItems, className } = props;
const [qspTab, setQspTab] = useQueryParam(qsp ?? QSP.TAB, StringParam);
@@ -31,7 +32,12 @@ export const Tabs = (props: TabsProps) => {
};
return (
-
+
diff --git a/frontend/app/src/components/ui/badge-copy.tsx b/frontend/app/src/components/ui/badge-copy.tsx
new file mode 100644
index 0000000000..1dbdadaf87
--- /dev/null
+++ b/frontend/app/src/components/ui/badge-copy.tsx
@@ -0,0 +1,17 @@
+import { ReactNode } from "react";
+import { CopyToClipboard } from "../buttons/copy-to-clipboard";
+
+interface BadgeCopyProps {
+ value: string;
+ children?: ReactNode;
+}
+
+export function BadgeCopy({ value, children }: BadgeCopyProps) {
+ return (
+
+
{children || value}
+
+
+
+ );
+}
diff --git a/frontend/app/src/components/ui/badge.tsx b/frontend/app/src/components/ui/badge.tsx
index d19f082634..0e263359eb 100644
--- a/frontend/app/src/components/ui/badge.tsx
+++ b/frontend/app/src/components/ui/badge.tsx
@@ -1,5 +1,5 @@
import { classNames } from "@/utils/common";
-import { cva, VariantProps } from "class-variance-authority";
+import { VariantProps, cva } from "class-variance-authority";
import React from "react";
const badgeVariants = cva(
diff --git a/frontend/app/src/components/breadcrumb/breadcrumb.tsx b/frontend/app/src/components/ui/breadcrumb.tsx
similarity index 64%
rename from frontend/app/src/components/breadcrumb/breadcrumb.tsx
rename to frontend/app/src/components/ui/breadcrumb.tsx
index e22c733adf..26fe47e444 100644
--- a/frontend/app/src/components/breadcrumb/breadcrumb.tsx
+++ b/frontend/app/src/components/ui/breadcrumb.tsx
@@ -1,8 +1,6 @@
-import React from "react";
import { classNames } from "@/utils/common";
import { Icon } from "@iconify-icon/react";
-import { Slot } from "@radix-ui/react-slot";
-import { Link, LinkProps } from "react-router-dom";
+import React from "react";
export const Breadcrumb = React.forwardRef
>(
({ className, ...props }, ref) => (
@@ -25,8 +23,9 @@ export const BreadcrumbSeparator = ({
role="presentation"
aria-hidden="true"
className={classNames("inline-flex", className)}
- {...props}>
- {children ?? }
+ {...props}
+ >
+ {children ?? }
);
@@ -39,23 +38,3 @@ export const BreadcrumbItem = React.forwardRef
)
);
-
-export const BreadcrumbLink = React.forwardRef<
- HTMLAnchorElement,
- LinkProps & {
- asChild?: boolean;
- }
->(({ asChild, className, ...props }, ref) => {
- const Comp = asChild ? Slot : Link;
-
- return (
-
- );
-});
diff --git a/frontend/app/src/components/ui/card.tsx b/frontend/app/src/components/ui/card.tsx
index c3191b238f..8e9dcca047 100644
--- a/frontend/app/src/components/ui/card.tsx
+++ b/frontend/app/src/components/ui/card.tsx
@@ -1,5 +1,5 @@
import { classNames } from "@/utils/common";
-import { forwardRef, HTMLAttributes } from "react";
+import { HTMLAttributes, forwardRef } from "react";
export interface CardProps extends HTMLAttributes {}
@@ -21,12 +21,14 @@ const CardWithBorderRoot = forwardRef(
+ {...props}
+ >
+ )}
+ >
{children}
diff --git a/frontend/app/src/components/ui/combobox-legacy.tsx b/frontend/app/src/components/ui/combobox-legacy.tsx
new file mode 100644
index 0000000000..19a253cc9e
--- /dev/null
+++ b/frontend/app/src/components/ui/combobox-legacy.tsx
@@ -0,0 +1,204 @@
+import { Button, ButtonProps } from "@/components/buttons/button-primitive";
+import { classNames } from "@/utils/common";
+import { Combobox as ComboboxPrimitive } from "@headlessui/react";
+import { Icon } from "@iconify-icon/react";
+import { PopoverTriggerProps } from "@radix-ui/react-popover";
+import React, { forwardRef, useState } from "react";
+import { Badge } from "./badge";
+import { Popover, PopoverContent, PopoverTrigger } from "./popover";
+import { SearchInput } from "./search-input";
+
+export interface MultiComboboxProps extends Omit {
+ children?: React.ReactNode;
+ placeholder?: string;
+ value: Array;
+ items?: ComboboxListProps["items"];
+ onChange?: (value: string[]) => void;
+}
+
+export const MultiCombobox = forwardRef(
+ ({ value = [], onChange, items = [], ...props }, ref) => {
+ const [open, setOpen] = React.useState(false);
+
+ const handleChange = (newValues: unknown) => {
+ if (onChange) onChange(newValues as string[]);
+ };
+
+ const selectedItems = items.filter((item) => value.includes(item.value)) ?? [];
+
+ return (
+
+
+
+
+ {selectedItems.map((item, index) => (
+ {item.label}
+ ))}
+
+
+
+ handleChange([])} />
+
+
+ );
+ }
+);
+
+export interface ComboboxProps extends Omit {
+ children?: React.ReactNode;
+ placeholder?: string;
+ items?: ComboboxListProps["items"];
+ onChange?: (value: string) => void;
+}
+
+export const Combobox = forwardRef(
+ ({ value, onChange, items = [], ...props }, ref) => {
+ const [open, setOpen] = React.useState(false);
+
+ const handleChange = (v: unknown) => {
+ if (onChange) onChange(v as string);
+ setOpen(false);
+ };
+
+ const item = items.find((item) => item.value === value);
+
+ return (
+
+
+
+
+ {item?.label || value}
+ {item?.badge && {item.badge}}
+
+
+
+
+
+
+ );
+ }
+);
+
+interface ComboboxTriggerProps extends PopoverTriggerProps {
+ value?: string;
+ placeholder?: string;
+}
+
+export const ComboboxTrigger = forwardRef(
+ ({ className, children, placeholder, ...props }, ref) => {
+ return (
+
+
+ {children || {placeholder}}
+
+
+
+ );
+ }
+);
+
+type ComboboxListProps = {
+ items: Array;
+ onReset: (value: unknown) => void;
+};
+
+export const ComboboxList = ({ items, onReset }: ComboboxListProps) => {
+ const [query, setQuery] = useState("");
+
+ const filteredOptions =
+ query === ""
+ ? items
+ : items.filter((item) => {
+ const matchLabel = item.label.toLowerCase().includes(query.toLowerCase());
+ const matchValue = item.value?.toLowerCase?.()?.includes(query.toLowerCase());
+
+ if (item.badge) {
+ return (
+ matchLabel || matchValue || item.badge.toLowerCase().includes(query.toLowerCase())
+ );
+ }
+
+ return matchLabel || matchValue;
+ });
+
+ return (
+ setQuery("")}
+ className="p-2 space-y-2 overflow-hidden flex flex-col"
+ style={{
+ width: "var(--radix-popover-trigger-width)",
+ maxHeight: "min(var(--radix-popover-content-available-height), 264px)",
+ }}
+ >
+
+
+ setQuery(event.target.value)}
+ />
+
+
onReset("")}>
+ Clear
+
+
+
+ {filteredOptions.length > 0 ? (
+
+ {filteredOptions.map((item, index) => {
+ return typeof item === "string" ? (
+
+ ) : (
+
+ );
+ })}
+
+ ) : (
+ Nothing found.
+ )}
+
+ );
+};
+
+export type tComboboxItem = { value: any; label: string; badge?: string };
+
+type ComboboxItemProps = {
+ className?: string;
+ item: tComboboxItem;
+};
+
+export const ComboboxItem = ({ className, item }: ComboboxItemProps) => {
+ return (
+
+ classNames(
+ "px-2 py-1.5 rounded mb-2 last:mb-0 cursor-pointer",
+ selected && "bg-sky-100",
+ active && "bg-gray-100",
+ className
+ )
+ }
+ value={item.value?.id || item.value}
+ >
+ {({ selected }) => (
+
+ {item.label}
+
+ {item.badge &&
{item.badge}}
+
+
{selected && }
+
+
+ )}
+
+ );
+};
diff --git a/frontend/app/src/components/ui/combobox.tsx b/frontend/app/src/components/ui/combobox.tsx
index e80081562f..7bf64c831a 100644
--- a/frontend/app/src/components/ui/combobox.tsx
+++ b/frontend/app/src/components/ui/combobox.tsx
@@ -1,201 +1,84 @@
-import { Button, ButtonProps } from "@/components/buttons/button-primitive";
+import {
+ Command,
+ CommandEmpty,
+ CommandInput,
+ CommandItem,
+ CommandList,
+} from "@/components/ui/command";
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { classNames } from "@/utils/common";
-import { Combobox as ComboboxPrimitive } from "@headlessui/react";
import { Icon } from "@iconify-icon/react";
import { PopoverTriggerProps } from "@radix-ui/react-popover";
-import React, { forwardRef, useState } from "react";
-import { Popover, PopoverContent, PopoverTrigger } from "./popover";
-import { SearchInput } from "./search-input";
-import { Badge } from "./badge";
+import React from "react";
-export interface MultiComboboxProps extends Omit {
- children?: React.ReactNode;
- placeholder?: string;
- value: Array;
- items?: ComboboxListProps["items"];
- onChange?: (value: string[]) => void;
-}
+export const Combobox = Popover;
-export const MultiCombobox = forwardRef(
- ({ value = [], onChange, items = [], ...props }, ref) => {
- const [open, setOpen] = React.useState(false);
+export interface ComboboxTriggerProps
+ extends PopoverTriggerProps,
+ React.HTMLAttributes {}
- const handleChange = (newValues: unknown) => {
- if (onChange) onChange(newValues as string[]);
- };
-
- const selectedItems = items.filter((item) => value.includes(item.value)) ?? [];
-
- return (
-
-
-
-
- {selectedItems.map((item, index) => (
- {item.label}
- ))}
-
-
-
- handleChange([])} />
-
-
- );
- }
-);
-
-export interface ComboboxProps extends Omit {
- children?: React.ReactNode;
- placeholder?: string;
- items?: ComboboxListProps["items"];
- onChange?: (value: string) => void;
-}
-
-export const Combobox = forwardRef(
- ({ value, onChange, items = [], ...props }, ref) => {
- const [open, setOpen] = React.useState(false);
-
- const handleChange = (v: unknown) => {
- if (onChange) onChange(v as string);
- setOpen(false);
- };
-
- const item = items.find((item) => item.value === value);
-
- return (
-
-
-
-
- {item?.label || value}
- {item?.badge && {item.badge}}
-
-
-
-
-
-
- );
- }
-);
-
-interface ComboboxTriggerProps extends PopoverTriggerProps {
- value?: string;
- placeholder?: string;
-}
-
-export const ComboboxTrigger = forwardRef(
- ({ className, children, placeholder, ...props }, ref) => {
+export const ComboboxTrigger = React.forwardRef(
+ ({ children, className, ...props }, ref) => {
return (
-
-
- {children || {placeholder}}
-
-
+
+
+ {children}
+
+
);
}
);
-type ComboboxListProps = {
- items: Array;
- onReset: (value: unknown) => void;
-};
-
-export const ComboboxList = ({ items, onReset }: ComboboxListProps) => {
- const [query, setQuery] = useState("");
-
- const filteredOptions =
- query === ""
- ? items
- : items.filter((item) => {
- const matchLabel = item.label.toLowerCase().includes(query.toLowerCase());
- const matchValue = item.value?.toLowerCase?.()?.includes(query.toLowerCase());
-
- if (item.badge) {
- return (
- matchLabel || matchValue || item.badge.toLowerCase().includes(query.toLowerCase())
- );
- }
-
- return matchLabel || matchValue;
- });
-
+export const ComboboxContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ ...props }, ref) => {
+ return ;
+});
+
+export const ComboboxList = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef & { fitTriggerWidth?: boolean }
+>(({ fitTriggerWidth = true, ...props }, ref) => {
return (
- setQuery("")}
- className="p-2 space-y-2 overflow-hidden flex flex-col"
+
-
-
- setQuery(event.target.value)}
- />
-
-
onReset("")}>
- Clear
-
-
-
- {filteredOptions.length > 0 ? (
-
- {filteredOptions.map((item, index) => {
- return typeof item === "string" ? (
-
- ) : (
-
- );
- })}
-
- ) : (
- Nothing found.
- )}
-
+ maxHeight: "min(var(--radix-popover-content-available-height), 300px)",
+ ...(fitTriggerWidth
+ ? { width: "var(--radix-popover-trigger-width)" }
+ : { minWidth: "var(--radix-popover-trigger-width)" }),
+ }}
+ >
+
+
+
);
-};
-
-export type tComboboxItem = { value: any; label: string; badge?: string };
-
-type ComboboxItemProps = {
- className?: string;
- item: tComboboxItem;
-};
+});
-export const ComboboxItem = ({ className, item }: ComboboxItemProps) => {
+export const ComboboxItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef & {
+ selectedValue?: string | null;
+ value: string;
+ }
+>(({ children, selectedValue, ...props }, ref) => {
return (
-
- classNames(
- "px-2 py-1.5 rounded mb-2 last:mb-0 cursor-pointer",
- selected && "bg-sky-100",
- active && "bg-gray-100",
- className
- )
- }
- value={item.value?.id || item.value}>
- {({ selected }) => (
-
- {item.label}
-
- {item.badge &&
{item.badge}}
-
-
{selected && }
-
-
- )}
-
+
+
+ {children}
+
);
-};
+});
+
+export const ComboboxEmpty = CommandEmpty;
diff --git a/frontend/app/src/components/ui/command.tsx b/frontend/app/src/components/ui/command.tsx
new file mode 100644
index 0000000000..031e355ba8
--- /dev/null
+++ b/frontend/app/src/components/ui/command.tsx
@@ -0,0 +1,67 @@
+import { classNames } from "@/utils/common";
+import { Icon } from "@iconify-icon/react";
+import { Command as CommandPrimitive } from "cmdk";
+import * as React from "react";
+
+export const Command = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+export const CommandInput = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+));
+
+export const CommandList = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+export const CommandItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+export const CommandEmpty = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>((props, ref) => (
+
+));
diff --git a/frontend/app/src/components/ui/divider.tsx b/frontend/app/src/components/ui/divider.tsx
new file mode 100644
index 0000000000..0e0b88bc5f
--- /dev/null
+++ b/frontend/app/src/components/ui/divider.tsx
@@ -0,0 +1,14 @@
+import { classNames } from "@/utils/common";
+import React from "react";
+
+export const Divider = ({ className, ...props }: React.HTMLAttributes) => {
+ return (
+
+ );
+};
diff --git a/frontend/app/src/components/ui/dropdown-menu.tsx b/frontend/app/src/components/ui/dropdown-menu.tsx
index 5fbfd586cc..ecef0df515 100644
--- a/frontend/app/src/components/ui/dropdown-menu.tsx
+++ b/frontend/app/src/components/ui/dropdown-menu.tsx
@@ -35,8 +35,8 @@ export const DropdownMenuItem = forwardRef<
ref={ref}
className={classNames(
"rounded-lg p-2",
- "text-neutral-800",
- "relative flex items-center",
+ "text-neutral-800 text-sm",
+ "relative flex items-center gap-2",
"cursor-pointer outline-none focus:bg-neutral-100",
"data-[disabled]:pointer-events-none data-[disabled]:opacity-40",
className
@@ -44,3 +44,14 @@ export const DropdownMenuItem = forwardRef<
{...props}
/>
));
+
+export const DropdownMenuDivider = forwardRef<
+ ElementRef,
+ ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
diff --git a/frontend/app/src/components/ui/form.tsx b/frontend/app/src/components/ui/form.tsx
index fec4d1d41d..85eb26f20a 100644
--- a/frontend/app/src/components/ui/form.tsx
+++ b/frontend/app/src/components/ui/form.tsx
@@ -1,4 +1,6 @@
import { Button, ButtonProps } from "@/components/buttons/button-primitive";
+import Label, { LabelProps } from "@/components/ui/label";
+import { Spinner } from "@/components/ui/spinner";
import { classNames } from "@/utils/common";
import { Slot } from "@radix-ui/react-slot";
import React, {
@@ -14,12 +16,10 @@ import {
Controller,
ControllerProps,
FormProvider,
+ UseFormReturn,
useForm,
useFormContext,
- UseFormReturn,
} from "react-hook-form";
-import { Spinner } from "@/components/ui/spinner";
-import Label, { LabelProps } from "@/components/ui/label";
import { SlideOverContext } from "../display/slide-over";
export type FormRef = ReturnType;
@@ -39,7 +39,7 @@ export const Form = React.forwardRef(
useImperativeHandle(ref, () => currentForm);
useEffect(() => {
- currentForm.reset(defaultValues);
+ if (!form) currentForm.reset(defaultValues);
}, [JSON.stringify(defaultValues)]);
useEffect(() => {
@@ -66,7 +66,8 @@ export const Form = React.forwardRef(
}
}}
className={classNames("space-y-4", className)}
- {...props}>
+ {...props}
+ >
{children}
@@ -110,6 +111,7 @@ export const FormInput = React.forwardRef<
error && "border-red-500 focus-visible:border-red-500 focus-visible:ring-red-500",
className
)}
+ aria-invalid={!!error}
{...props}
/>
);
@@ -133,7 +135,8 @@ export const FormMessage = ({
+ {...props}
+ >
{message}
);
diff --git a/frontend/app/src/components/ui/input.tsx b/frontend/app/src/components/ui/input.tsx
index 30da7c3e72..7185980083 100644
--- a/frontend/app/src/components/ui/input.tsx
+++ b/frontend/app/src/components/ui/input.tsx
@@ -1,5 +1,5 @@
import { classNames } from "@/utils/common";
-import { forwardRef, InputHTMLAttributes } from "react";
+import { InputHTMLAttributes, forwardRef } from "react";
export interface InputProps extends InputHTMLAttributes {}
diff --git a/frontend/app/src/components/ui/kbd.tsx b/frontend/app/src/components/ui/kbd.tsx
index 972d73d9ce..d3f82c4d80 100644
--- a/frontend/app/src/components/ui/kbd.tsx
+++ b/frontend/app/src/components/ui/kbd.tsx
@@ -1,5 +1,5 @@
import { classNames } from "@/utils/common";
-import { forwardRef, HTMLAttributes, useMemo } from "react";
+import { HTMLAttributes, forwardRef, useMemo } from "react";
export type KbdKey =
| "command"
@@ -48,7 +48,8 @@ const Kbd = forwardRef((props, ref) => {
+ className={classNames("no-underline", keyClassName)}
+ >
{kbdKeysMap[key]}
));
@@ -60,7 +61,8 @@ const Kbd = forwardRef((props, ref) => {
className={classNames(
"text-gray-600 bg-gray-100 font-sans py-0.5 px-1.5 rounded text-xs",
className
- )}>
+ )}
+ >
{keysContent}
{children && {children}}
diff --git a/frontend/app/src/components/ui/label.tsx b/frontend/app/src/components/ui/label.tsx
index 6fd3ab4af4..eb557b36bf 100644
--- a/frontend/app/src/components/ui/label.tsx
+++ b/frontend/app/src/components/ui/label.tsx
@@ -1,7 +1,7 @@
-import * as React from "react";
-import * as LabelPrimitive from "@radix-ui/react-label";
-import { cva, type VariantProps } from "class-variance-authority";
import { classNames } from "@/utils/common";
+import * as LabelPrimitive from "@radix-ui/react-label";
+import { type VariantProps, cva } from "class-variance-authority";
+import * as React from "react";
export interface LabelProps
extends React.ComponentPropsWithoutRef,
diff --git a/frontend/app/src/components/ui/link.tsx b/frontend/app/src/components/ui/link.tsx
index 6e5b458383..af04322e02 100644
--- a/frontend/app/src/components/ui/link.tsx
+++ b/frontend/app/src/components/ui/link.tsx
@@ -14,7 +14,8 @@ export const Link = (props: LinkProps) => {
return (
+ className={classNames("cursor-pointer underline hover:bg-gray-50 rounded-md", className)}
+ >
{children}
);
diff --git a/frontend/app/src/components/ui/pagination.tsx b/frontend/app/src/components/ui/pagination.tsx
index 18c8e8a8fa..837fb81a28 100644
--- a/frontend/app/src/components/ui/pagination.tsx
+++ b/frontend/app/src/components/ui/pagination.tsx
@@ -88,7 +88,8 @@ export const Pagination = (props: tPaginationType) => {
className={classNames(
"sticky bottom-0 flex items-center justify-between bg-custom-white p-2",
className
- )}>
+ )}
+ >
{paginationText}
diff --git a/frontend/app/src/components/ui/password-input.tsx b/frontend/app/src/components/ui/password-input.tsx
index d288ca408b..d62515b2e3 100644
--- a/frontend/app/src/components/ui/password-input.tsx
+++ b/frontend/app/src/components/ui/password-input.tsx
@@ -23,7 +23,8 @@ export const PasswordInput = forwardRef
(
onClick={() => setShowPassword((v) => !v)}
size="icon"
variant="ghost"
- className="h-10 absolute top-0 end-0 p-3.5 rounded-md hover:bg-transparent">
+ className="h-10 absolute top-0 end-0 p-3.5 rounded-md hover:bg-transparent"
+ >
diff --git a/frontend/app/src/components/ui/popover.tsx b/frontend/app/src/components/ui/popover.tsx
index 4480787206..3560b1e3da 100644
--- a/frontend/app/src/components/ui/popover.tsx
+++ b/frontend/app/src/components/ui/popover.tsx
@@ -10,18 +10,22 @@ export const PopoverAnchor = PopoverPrimitive.Anchor;
export const PopoverContent = React.forwardRef<
React.ElementRef
,
- PopoverPrimitive.PopoverContentProps
->(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
-
-
-
-));
+ PopoverPrimitive.PopoverContentProps & { portal?: boolean }
+>(({ className, align = "center", sideOffset = 4, portal = true, ...props }, ref) => {
+ const Wrapper = portal ? PopoverPrimitive.Portal : React.Fragment;
+
+ return (
+
+
+
+ );
+});
diff --git a/frontend/app/src/components/ui/spinner.tsx b/frontend/app/src/components/ui/spinner.tsx
index 3261665b0b..6b7e4d7ef1 100644
--- a/frontend/app/src/components/ui/spinner.tsx
+++ b/frontend/app/src/components/ui/spinner.tsx
@@ -10,7 +10,8 @@ export const Spinner = ({ ...props }: SpinnerProps) => {
className={classNames("w-4 h-4 text-gray-200 animate-spin fill-custom-blue-600")}
viewBox="0 0 100 101"
fill="none"
- xmlns="http://www.w3.org/2000/svg">
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ {...props}
+ >
{content}
diff --git a/frontend/app/src/components/ui/transition.tsx b/frontend/app/src/components/ui/transition.tsx
index 306830d5be..cfb38238ed 100644
--- a/frontend/app/src/components/ui/transition.tsx
+++ b/frontend/app/src/components/ui/transition.tsx
@@ -9,7 +9,8 @@ export default function Transition(props: any) {
leave="transition-opacity duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
- {...props}>
+ {...props}
+ >
{props.children}
);
diff --git a/frontend/app/src/components/ui/tree.tsx b/frontend/app/src/components/ui/tree.tsx
index b47dfa1f79..245c58eafa 100644
--- a/frontend/app/src/components/ui/tree.tsx
+++ b/frontend/app/src/components/ui/tree.tsx
@@ -49,7 +49,8 @@ const TreeItemWrapper = (props: INodeRendererProps & { children: React.ReactNode
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-custom-blue-500",
isSelected ? "bg-gray-200" : "hover:bg-gray-100",
isHalfSelected && "bg-gray-50"
- )}>
+ )}
+ >
{isBranch ? (
(
height="6"
viewBox="0 0 6 6"
fill="currentColor"
- xmlns="http://www.w3.org/2000/svg">
+ xmlns="http://www.w3.org/2000/svg"
+ >
;
-}
-
const GET_BRANCHES = gql`
query GetBranches {
Branch {
diff --git a/frontend/app/src/graphql/queries/objects/dropdownOptionsForRelatedPeers.ts b/frontend/app/src/graphql/queries/objects/dropdownOptionsForRelatedPeers.ts
index c385cec091..7e10148db5 100644
--- a/frontend/app/src/graphql/queries/objects/dropdownOptionsForRelatedPeers.ts
+++ b/frontend/app/src/graphql/queries/objects/dropdownOptionsForRelatedPeers.ts
@@ -9,8 +9,7 @@ export interface iPeerDropdownOptions {
[peer: string]: iPeerDropdownOption[];
}
-export const getDropdownOptionsForRelatedPeersPaginated =
- Handlebars.compile(`query DropdownFormOptions {
+export const getDropdownOptionsForRelatedPeersPaginated = Handlebars.compile(`query DropdownFormOptions {
{{#each peers}}
{{this}} {
count
diff --git a/frontend/app/src/graphql/queries/proposed-changes/getProposedChangesDetails.ts b/frontend/app/src/graphql/queries/proposed-changes/getProposedChangesDetails.ts
index 57e936e83e..41feb610e1 100644
--- a/frontend/app/src/graphql/queries/proposed-changes/getProposedChangesDetails.ts
+++ b/frontend/app/src/graphql/queries/proposed-changes/getProposedChangesDetails.ts
@@ -1,5 +1,5 @@
-import Handlebars from "handlebars";
import { gql } from "@apollo/client";
+import Handlebars from "handlebars";
export const getProposedChanges = Handlebars.compile(`
query GET_PROPOSED_CHANGES($id: ID, $nodeId: String, $state: String) {
diff --git a/frontend/app/src/graphql/queries/role-management/getAccounts.ts b/frontend/app/src/graphql/queries/role-management/getAccounts.ts
new file mode 100644
index 0000000000..58523f8d20
--- /dev/null
+++ b/frontend/app/src/graphql/queries/role-management/getAccounts.ts
@@ -0,0 +1,26 @@
+import { gql } from "@apollo/client";
+
+export const GET_ROLE_MANAGEMENT_ACCOUNTS = gql`
+ query GET_ROLE_MANAGEMENT_ACCOUNTS {
+ CoreGenericAccount {
+ count
+ edges {
+ node {
+ id
+ description {
+ value
+ }
+ display_label
+ account_type {
+ value
+ }
+ status {
+ value
+ color
+ description
+ }
+ }
+ }
+ }
+ }
+`;
diff --git a/frontend/app/src/graphql/queries/role-management/getCounts.ts b/frontend/app/src/graphql/queries/role-management/getCounts.ts
new file mode 100644
index 0000000000..b2eab1acac
--- /dev/null
+++ b/frontend/app/src/graphql/queries/role-management/getCounts.ts
@@ -0,0 +1,21 @@
+import { gql } from "@apollo/client";
+
+export const GET_ROLE_MANAGEMENT_COUNTS = gql`
+ query GET_ROLE_MANAGEMENT_COUNTS {
+ CoreAccountRole {
+ count
+ }
+ CoreAccountGroup {
+ count
+ }
+ CoreGlobalPermission {
+ count
+ }
+ CoreObjectPermission {
+ count
+ }
+ CoreGenericAccount {
+ count
+ }
+ }
+`;
diff --git a/frontend/app/src/graphql/queries/role-management/getGlobalPermissions.ts b/frontend/app/src/graphql/queries/role-management/getGlobalPermissions.ts
new file mode 100644
index 0000000000..9f5734837b
--- /dev/null
+++ b/frontend/app/src/graphql/queries/role-management/getGlobalPermissions.ts
@@ -0,0 +1,24 @@
+import { gql } from "@apollo/client";
+
+export const GET_ROLE_MANAGEMENT_GLOBAL_PERMISSIONS = gql`
+ query GET_ROLE_MANAGEMENT_GLOBAL_PERMISSIONS {
+ CoreGlobalPermission {
+ edges {
+ node {
+ id
+ display_label
+ action {
+ value
+ }
+ roles {
+ count
+ }
+ identifier {
+ value
+ }
+ __typename
+ }
+ }
+ }
+ }
+`;
diff --git a/frontend/app/src/graphql/queries/role-management/getGroups.ts b/frontend/app/src/graphql/queries/role-management/getGroups.ts
new file mode 100644
index 0000000000..774e23e17d
--- /dev/null
+++ b/frontend/app/src/graphql/queries/role-management/getGroups.ts
@@ -0,0 +1,27 @@
+import { gql } from "@apollo/client";
+
+export const GET_ROLE_MANAGEMENT_GROUPS = gql`
+ query GET_ROLE_MANAGEMENT_GROUPS {
+ CoreAccountGroup {
+ edges {
+ node {
+ id
+ display_label
+ description {
+ value
+ }
+ group_type {
+ value
+ }
+ members {
+ edges {
+ node {
+ display_label
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+`;
diff --git a/frontend/app/src/graphql/queries/role-management/getObjectPermissions.ts b/frontend/app/src/graphql/queries/role-management/getObjectPermissions.ts
new file mode 100644
index 0000000000..ddd814f706
--- /dev/null
+++ b/frontend/app/src/graphql/queries/role-management/getObjectPermissions.ts
@@ -0,0 +1,35 @@
+import { gql } from "@apollo/client";
+
+export const GET_ROLE_MANAGEMENT_OBJECT_PERMISSIONS = gql`
+ query GET_ROLE_MANAGEMENT_OBJECT_PERMISSIONS {
+ CoreObjectPermission {
+ edges {
+ node {
+ id
+ display_label
+ name {
+ value
+ }
+ branch {
+ value
+ }
+ namespace {
+ value
+ }
+ action {
+ value
+ }
+ decision {
+ value
+ }
+ roles {
+ count
+ }
+ identifier {
+ value
+ }
+ }
+ }
+ }
+ }
+`;
diff --git a/frontend/app/src/graphql/queries/role-management/getRoles.ts b/frontend/app/src/graphql/queries/role-management/getRoles.ts
new file mode 100644
index 0000000000..fadbccafe8
--- /dev/null
+++ b/frontend/app/src/graphql/queries/role-management/getRoles.ts
@@ -0,0 +1,20 @@
+import { gql } from "@apollo/client";
+
+export const GET_ROLE_MANAGEMENT_ROLES = gql`
+ query GET_ROLE_MANAGEMENT_ROLES {
+ CoreAccountRole {
+ edges {
+ node {
+ id
+ display_label
+ groups {
+ count
+ }
+ permissions {
+ count
+ }
+ }
+ }
+ }
+ }
+`;
diff --git a/frontend/app/src/graphql/utils.ts b/frontend/app/src/graphql/utils.ts
index 647094ff12..57fe7b6a1a 100644
--- a/frontend/app/src/graphql/utils.ts
+++ b/frontend/app/src/graphql/utils.ts
@@ -1,5 +1,5 @@
-import { components } from "@/infraops";
import { SCHEMA_ATTRIBUTE_KIND } from "@/config/constants";
+import { components } from "@/infraops";
export const addAttributesToRequest = (
attributes: components["schemas"]["AttributeSchema-Output"][]
diff --git a/frontend/app/src/hooks/useAuth.tsx b/frontend/app/src/hooks/useAuth.tsx
index 54e1c6e668..2a67edc952 100644
--- a/frontend/app/src/hooks/useAuth.tsx
+++ b/frontend/app/src/hooks/useAuth.tsx
@@ -1,4 +1,4 @@
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { CONFIG } from "@/config/config";
import { ACCESS_TOKEN_KEY, ADMIN_ROLES, REFRESH_TOKEN_KEY, WRITE_ROLES } from "@/config/constants";
import { components } from "@/infraops";
@@ -6,7 +6,7 @@ import { configState } from "@/state/atoms/config.atom";
import { parseJwt } from "@/utils/common";
import { fetchUrl } from "@/utils/fetch";
import { useAtom } from "jotai/index";
-import { createContext, ReactElement, ReactNode, useContext, useState } from "react";
+import { ReactElement, ReactNode, createContext, useContext, useState } from "react";
import { Navigate, useLocation } from "react-router-dom";
import { toast } from "react-toastify";
@@ -19,6 +19,11 @@ type User = {
id: string;
};
+type UserToken = {
+ access_token: string;
+ refresh_token: string;
+};
+
export type AuthContextType = {
accessToken: string | null;
data?: any;
@@ -27,6 +32,7 @@ export type AuthContextType = {
permissions?: PermissionsType;
signIn: (data: { username: string; password: string }, callback?: () => void) => Promise;
signOut: (callback?: () => void) => void;
+ setToken: (token: UserToken) => void;
user: User | null;
};
@@ -86,6 +92,7 @@ export const AuthContext = createContext({
},
signIn: async () => {},
signOut: () => {},
+ setToken: () => {},
user: null,
});
@@ -94,6 +101,11 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const [accessToken, setAccessToken] = useState(localToken);
const [isLoading, setIsLoading] = useState(false);
+ const setToken = (token: UserToken) => {
+ setAccessToken(token.access_token);
+ saveTokensInLocalStorage(token);
+ };
+
const signIn = async (data: { username: string; password: string }, callback?: () => void) => {
const payload = {
method: "POST",
@@ -115,8 +127,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
return;
}
- setAccessToken(result?.access_token);
- saveTokensInLocalStorage(result);
+ setToken(result);
if (callback) callback();
};
@@ -138,6 +149,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
},
signIn,
signOut,
+ setToken,
user: data?.sub ? { id: data?.sub } : null,
};
diff --git a/frontend/app/src/hooks/useCodeMirror.ts b/frontend/app/src/hooks/useCodeMirror.ts
index 75c0a86776..0a53c8571f 100644
--- a/frontend/app/src/hooks/useCodeMirror.ts
+++ b/frontend/app/src/hooks/useCodeMirror.ts
@@ -1,6 +1,8 @@
import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
import { markdown, markdownKeymap, markdownLanguage } from "@codemirror/lang-markdown";
+import { syntaxHighlighting } from "@codemirror/language";
import { EditorState } from "@codemirror/state";
+import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
import {
EditorView,
ViewUpdate,
@@ -8,11 +10,9 @@ import {
lineNumbers,
placeholder as placeholderView,
} from "@codemirror/view";
+import { graphql } from "cm6-graphql";
import { basicLight } from "cm6-theme-basic-light";
import { useEffect, useState } from "react";
-import { syntaxHighlighting } from "@codemirror/language";
-import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
-import { graphql } from "cm6-graphql";
export type UseCodeMirror = {
editor?: HTMLDivElement | null;
diff --git a/frontend/app/src/hooks/useFormValues.ts b/frontend/app/src/hooks/useFormValues.ts
deleted file mode 100644
index 109651a7ad..0000000000
--- a/frontend/app/src/hooks/useFormValues.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { useFormContext, useWatch } from "react-hook-form";
-
-// Used to retrieve and watch values from form context
-export const useFormValues = () => {
- const { getValues } = useFormContext();
-
- return {
- ...useWatch(), // subscribe to form value updates
- ...getValues(), // always merge with latest form values
- };
-};
diff --git a/frontend/app/src/hooks/useObjectDetails.ts b/frontend/app/src/hooks/useObjectDetails.ts
index e15a549d50..be4a6c7f39 100644
--- a/frontend/app/src/hooks/useObjectDetails.ts
+++ b/frontend/app/src/hooks/useObjectDetails.ts
@@ -1,11 +1,11 @@
-import { gql } from "@apollo/client";
-import { useAtomValue } from "jotai";
-import useQuery from "@/hooks/useQuery";
-import { genericsState, IModelSchema } from "@/state/atoms/schema.atom";
-import { getObjectDetailsPaginated } from "@/graphql/queries/objects/getObjectDetails";
import { PROFILE_KIND, TASK_OBJECT } from "@/config/constants";
-import { getSchemaObjectColumns, getTabs } from "@/utils/getSchemaObjectColumns";
+import { getObjectDetailsPaginated } from "@/graphql/queries/objects/getObjectDetails";
+import useQuery from "@/hooks/useQuery";
+import { IModelSchema, genericsState } from "@/state/atoms/schema.atom";
import { isGeneric } from "@/utils/common";
+import { getSchemaObjectColumns, getTabs } from "@/utils/getSchemaObjectColumns";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai";
export const useObjectDetails = (schema: IModelSchema, objectId: string) => {
const generics = useAtomValue(genericsState);
diff --git a/frontend/app/src/hooks/useObjectItems.ts b/frontend/app/src/hooks/useObjectItems.ts
index 77bc84f97d..b8b41e5f5d 100644
--- a/frontend/app/src/hooks/useObjectItems.ts
+++ b/frontend/app/src/hooks/useObjectItems.ts
@@ -1,12 +1,12 @@
+import { ACCOUNT_TOKEN_OBJECT } from "@/config/constants";
+import { getTokens } from "@/graphql/queries/accounts/getTokens";
+import { getObjectItemsPaginated } from "@/graphql/queries/objects/getObjectItems";
+import { Filter } from "@/hooks/useFilters";
import useQuery from "@/hooks/useQuery";
import { IModelSchema, genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
-import { getObjectItemsPaginated } from "@/graphql/queries/objects/getObjectItems";
import { getObjectAttributes, getObjectRelationships } from "@/utils/getSchemaObjectColumns";
-import { Filter } from "@/hooks/useFilters";
-import { useAtomValue } from "jotai";
-import { ACCOUNT_TOKEN_OBJECT } from "@/config/constants";
-import { getTokens } from "@/graphql/queries/accounts/getTokens";
import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai";
const getQuery = (schema?: IModelSchema, filters?: Array) => {
if (!schema) return "query {ok}";
diff --git a/frontend/app/src/hooks/useQuery.ts b/frontend/app/src/hooks/useQuery.ts
index 8f1a123eb0..2edb7abc08 100644
--- a/frontend/app/src/hooks/useQuery.ts
+++ b/frontend/app/src/hooks/useQuery.ts
@@ -5,8 +5,8 @@ import { datetimeAtom } from "@/state/atoms/time.atom";
import {
OperationVariables,
useLazyQuery as useApolloLazyQuery,
- useQuery as useApolloQuery,
useMutation as useApolloMutation,
+ useQuery as useApolloQuery,
useSubscription as useApolloSubscription,
} from "@apollo/client";
import { useAtomValue } from "jotai";
diff --git a/frontend/app/src/hooks/useSchema.ts b/frontend/app/src/hooks/useSchema.ts
index 3d49885be0..b1985b0036 100644
--- a/frontend/app/src/hooks/useSchema.ts
+++ b/frontend/app/src/hooks/useSchema.ts
@@ -1,12 +1,12 @@
-import { useAtomValue } from "jotai/index";
import {
+ IProfileSchema,
genericsState,
iGenericSchema,
iNodeSchema,
- IProfileSchema,
profilesAtom,
schemaState,
} from "@/state/atoms/schema.atom";
+import { useAtomValue } from "jotai/index";
type UseSchema = (kind?: string) =>
| {
diff --git a/frontend/app/src/images/infrahub-logo.svg b/frontend/app/src/images/infrahub-logo.svg
new file mode 100644
index 0000000000..f5486c1ccd
--- /dev/null
+++ b/frontend/app/src/images/infrahub-logo.svg
@@ -0,0 +1,33 @@
+
+
diff --git a/frontend/app/src/main.tsx b/frontend/app/src/main.tsx
index 25b487aeee..b425c732db 100644
--- a/frontend/app/src/main.tsx
+++ b/frontend/app/src/main.tsx
@@ -1,5 +1,5 @@
-import ReactDOM from "react-dom/client";
import { App } from "@/App";
+import ReactDOM from "react-dom/client";
// https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react#consistent-components-exports
ReactDOM.createRoot(document.getElementById("root")!).render();
diff --git a/frontend/app/src/pages/auth-callback.tsx b/frontend/app/src/pages/auth-callback.tsx
new file mode 100644
index 0000000000..b59b0222d6
--- /dev/null
+++ b/frontend/app/src/pages/auth-callback.tsx
@@ -0,0 +1,63 @@
+import { INFRAHUB_API_SERVER_URL } from "@/config/config";
+import { useAuth } from "@/hooks/useAuth";
+import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import { configState } from "@/state/atoms/config.atom";
+import { fetchUrl } from "@/utils/fetch";
+import { useAtomValue } from "jotai";
+import { useEffect, useState } from "react";
+import { Navigate, useParams, useSearchParams } from "react-router-dom";
+
+function AuthCallback() {
+ const { protocol, provider } = useParams();
+ const config = useAtomValue(configState);
+ const [searchParams] = useSearchParams();
+ const { isAuthenticated, setToken } = useAuth();
+ const [redirectTo, setRedirectTo] = useState("/");
+ const [errors, setErrors] = useState(null);
+
+ const code = searchParams.get("code");
+ const state = searchParams.get("state");
+
+ useEffect(() => {
+ if (!config || !config.sso.enabled) return;
+
+ const currentAuthProvider = config.sso.providers.find(
+ (p) => p.protocol === protocol && p.name === provider
+ );
+ if (!currentAuthProvider) return;
+
+ const { token_path } = currentAuthProvider;
+ fetchUrl(`${INFRAHUB_API_SERVER_URL}${token_path}?code=${code}&state=${state}`)
+ .then((result) => {
+ if (result.errors) {
+ throw result;
+ }
+
+ setRedirectTo(result.final_url);
+ setToken(result);
+ })
+ .catch((error) => {
+ setErrors(error.errors);
+ });
+ }, [config, protocol, provider]);
+
+ if (!config || !config.sso.enabled) {
+ return ;
+ }
+
+ if (errors) {
+ return ;
+ }
+
+ if (isAuthenticated) {
+ return ;
+ }
+
+ return (
+
+
+
+ );
+}
+
+export const Component = AuthCallback;
diff --git a/frontend/app/src/pages/branches/details.tsx b/frontend/app/src/pages/branches/details.tsx
index 702c2b8a8e..aff734ee5b 100644
--- a/frontend/app/src/pages/branches/details.tsx
+++ b/frontend/app/src/pages/branches/details.tsx
@@ -4,30 +4,14 @@ import { QSP } from "@/config/qsp";
import { ArtifactsDiff } from "@/screens/diff/artifact-diff/artifacts-diff";
import { NodeDiff } from "@/screens/diff/node-diff";
+import { useTitle } from "@/hooks/useTitle";
+import { BranchDetails } from "@/screens/branches/branch-details";
import { FilesDiff } from "@/screens/diff/file-diff/files-diff";
import Content from "@/screens/layout/content";
import { constructPath } from "@/utils/fetch";
-import { Icon } from "@iconify-icon/react";
-import { BranchDetails } from "@/screens/branches/branch-details";
-import { Link, Navigate, useParams } from "react-router-dom";
-import { StringParam, useQueryParam } from "use-query-params";
-import { useTitle } from "@/hooks/useTitle";
-import { Button } from "@/components/buttons/button-primitive";
import React from "react";
-import {
- Breadcrumb,
- BreadcrumbItem,
- BreadcrumbLink,
- BreadcrumbSeparator,
-} from "@/components/breadcrumb/breadcrumb";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu";
-import { useAtomValue } from "jotai";
-import { branchesState } from "@/state/atoms/branches.atom";
+import { Navigate, useParams } from "react-router-dom";
+import { StringParam, useQueryParam } from "use-query-params";
export const BRANCH_TABS = {
DETAILS: "details",
@@ -44,19 +28,7 @@ export function BranchDetailsPage() {
return (
-
- Branches
-
-
-
-
-
-
-
- }
- />
+ Branch - {branchName} } />
@@ -65,31 +37,6 @@ export function BranchDetailsPage() {
);
}
-const BranchSelectorBreadcrumb = ({ branchName }: { branchName: string }) => {
- const branches = useAtomValue(branchesState);
-
- return (
-
-
-
- {branchName}
-
-
-
-
-
- {branches.map((branch) => (
-
-
- {branch.name}
-
-
- ))}
-
-
- );
-};
-
const BranchTab = () => {
const tabs = [
{
diff --git a/frontend/app/src/pages/homepage.tsx b/frontend/app/src/pages/homepage.tsx
index 165b70d54e..5bcf54534a 100644
--- a/frontend/app/src/pages/homepage.tsx
+++ b/frontend/app/src/pages/homepage.tsx
@@ -1,32 +1,35 @@
+import { Card } from "@/components/ui/card";
import Content from "@/screens/layout/content";
import { Icon } from "@iconify-icon/react";
import { Link } from "react-router-dom";
const Homepage = () => {
return (
-
-
-
Welcome to Infrahub!
+
+
+
Welcome to Infrahub!
Browse our{" "}
+ className="text-custom-blue-700 font-semibold"
+ >
documentation
{" "}
or{" "}
+ className="text-custom-blue-700 font-semibold"
+ >
tutorials
{" "}
to start using Infrahub.
-
+
{
/>
-
+
Infrahub Integrations
Integrate Infrahub with other tools and solutions. Below is a list of OpsMill-maintained
@@ -64,7 +67,7 @@ const Homepage = () => {
-
+
{
return (
-
-
+
+
{title}
{description}
-
+
{docTo && (
@@ -135,7 +138,7 @@ const HelperCard = ({
)}
-
+
);
};
diff --git a/frontend/app/src/pages/ipam/layout.tsx b/frontend/app/src/pages/ipam/layout.tsx
index bae69483ac..e7d6960a0e 100644
--- a/frontend/app/src/pages/ipam/layout.tsx
+++ b/frontend/app/src/pages/ipam/layout.tsx
@@ -8,7 +8,7 @@ import IpamTree from "../../screens/ipam/ipam-tree/ipam-tree";
function IpamLayout() {
return (
<>
-
+ IP Address Manager}>
diff --git a/frontend/app/src/pages/objects/CoreGraphQLQuery/graphql-query-details.tsx b/frontend/app/src/pages/objects/CoreGraphQLQuery/graphql-query-details.tsx
index bbce532239..00e2219d5c 100644
--- a/frontend/app/src/pages/objects/CoreGraphQLQuery/graphql-query-details.tsx
+++ b/frontend/app/src/pages/objects/CoreGraphQLQuery/graphql-query-details.tsx
@@ -53,7 +53,8 @@ const GraphqlQueryDetailsPage = () => {
+ className="hover:underline"
+ >
{graphqlQuerySchema.label}
@@ -69,7 +70,8 @@ const GraphqlQueryDetailsPage = () => {
}
reload={() => refetch()}
- isReloadLoading={loading}>
+ isReloadLoading={loading}
+ >
{
const { objectKind, objectid } = useParams();
diff --git a/frontend/app/src/pages/objects/object-details.tsx b/frontend/app/src/pages/objects/object-details.tsx
index 3566c9d43d..994901e7d1 100644
--- a/frontend/app/src/pages/objects/object-details.tsx
+++ b/frontend/app/src/pages/objects/object-details.tsx
@@ -1,16 +1,16 @@
-import { useParams } from "react-router-dom";
-import Content from "@/screens/layout/content";
-import { useAtomValue } from "jotai";
-import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
-import ObjectItems from "@/screens/object-items/object-items-paginated";
-import ErrorScreen from "@/screens/errors/error-screen";
+import { Card } from "@/components/ui/card";
+import { TASK_OBJECT } from "@/config/constants";
import { useObjectDetails } from "@/hooks/useObjectDetails";
+import ErrorScreen from "@/screens/errors/error-screen";
import NoDataFound from "@/screens/errors/no-data-found";
+import Content from "@/screens/layout/content";
+import LoadingScreen from "@/screens/loading-screen/loading-screen";
import ObjectItemDetails from "@/screens/object-item-details/object-item-details-paginated";
+import ObjectItems from "@/screens/object-items/object-items-paginated";
+import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
import { NetworkStatus } from "@apollo/client";
-import LoadingScreen from "@/screens/loading-screen/loading-screen";
-import { TASK_OBJECT } from "@/config/constants";
-import { Card } from "@/components/ui/card";
+import { useAtomValue } from "jotai";
+import { useParams } from "react-router-dom";
export function ObjectDetailsPage() {
const { objectKind, objectid } = useParams();
diff --git a/frontend/app/src/pages/objects/object-items.tsx b/frontend/app/src/pages/objects/object-items.tsx
index b466b1a68a..aabc4d5c49 100644
--- a/frontend/app/src/pages/objects/object-items.tsx
+++ b/frontend/app/src/pages/objects/object-items.tsx
@@ -2,9 +2,9 @@ import { useAtomValue } from "jotai";
import { useParams } from "react-router-dom";
import ErrorScreen from "@/screens/errors/error-screen";
+import Content from "@/screens/layout/content";
import ObjectItems from "@/screens/object-items/object-items-paginated";
import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
-import Content from "@/screens/layout/content";
export function ObjectItemsPage() {
const { objectKind } = useParams();
diff --git a/frontend/app/src/pages/proposed-changes/details.tsx b/frontend/app/src/pages/proposed-changes/details.tsx
index 30b2da10e7..f4634a2e98 100644
--- a/frontend/app/src/pages/proposed-changes/details.tsx
+++ b/frontend/app/src/pages/proposed-changes/details.tsx
@@ -8,26 +8,26 @@ import { ArtifactsDiff } from "@/screens/diff/artifact-diff/artifacts-diff";
import { Checks } from "@/screens/diff/checks/checks";
import { NodeDiff } from "@/screens/diff/node-diff";
+import { ObjectHelpButton } from "@/components/menu/object-help-button";
+import { Badge } from "@/components/ui/badge";
+import { CoreProposedChange } from "@/generated/graphql";
+import { useSchema } from "@/hooks/useSchema";
import { FilesDiff } from "@/screens/diff/file-diff/files-diff";
import ErrorScreen from "@/screens/errors/error-screen";
+import NoDataFound from "@/screens/errors/no-data-found";
import Content from "@/screens/layout/content";
+import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import { ProposedChangesChecksTab } from "@/screens/proposed-changes/checks-tab";
+import { ProposedChangeDetails } from "@/screens/proposed-changes/proposed-change-details";
import { TaskItemDetails } from "@/screens/tasks/task-item-details";
import { TaskItems } from "@/screens/tasks/task-items";
import { proposedChangedState } from "@/state/atoms/proposedChanges.atom";
import { constructPath } from "@/utils/fetch";
+import { getObjectDetailsUrl } from "@/utils/objects";
import { Icon } from "@iconify-icon/react";
import { useAtom } from "jotai";
import { Link, useLocation, useParams } from "react-router-dom";
import { StringParam, useQueryParam } from "use-query-params";
-import LoadingScreen from "@/screens/loading-screen/loading-screen";
-import { ProposedChangesChecksTab } from "@/screens/proposed-changes/checks-tab";
-import { ProposedChangeDetails } from "@/screens/proposed-changes/proposed-change-details";
-import { CoreProposedChange } from "@/generated/graphql";
-import { Badge } from "@/components/ui/badge";
-import { getObjectDetailsUrl } from "@/utils/objects";
-import { ObjectHelpButton } from "@/components/menu/object-help-button";
-import { useSchema } from "@/hooks/useSchema";
-import NoDataFound from "@/screens/errors/no-data-found";
export const PROPOSED_CHANGES_TABS = {
CONVERSATIONS: "conversations",
@@ -86,7 +86,8 @@ const ProposedChangeDetailsContent = ({ proposedChangeData }: ProposedChangesDet
{ name: QSP.PROPOSED_CHANGES_TAB, value: TASK_TAB },
{ name: QSP.TASK_ID, exclude: true },
])}
- className="flex items-center p-2 ">
+ className="flex items-center p-2 "
+ >
All tasks
@@ -159,13 +160,15 @@ export function Component() {
+ to={constructPath("/proposed-changes")}
+ >
Proposed changes
}
reload={() => client.reFetchObservableQueries()}
- isReloadLoading={loading}>
+ isReloadLoading={loading}
+ >
-
- Proposed changes
-
-
-
-
- {proposedChangesData.display_label}
-
- }
+ title={{proposedChangesData.display_label}
}
description={
+ className="font-semibold text-custom-blue-green"
+ >
{proposedChangesData?.created_by?.node?.display_label}
wants to merge
@@ -225,7 +219,8 @@ export function Component() {
}
reload={() => client.reFetchObservableQueries()}
- isReloadLoading={loading}>
+ isReloadLoading={loading}
+ >
{
const generics = useAtomValue(genericsState);
diff --git a/frontend/app/src/pages/resource-manager/resource-allocation-details.tsx b/frontend/app/src/pages/resource-manager/resource-allocation-details.tsx
index 0544372407..c25fa9a2c1 100644
--- a/frontend/app/src/pages/resource-manager/resource-allocation-details.tsx
+++ b/frontend/app/src/pages/resource-manager/resource-allocation-details.tsx
@@ -6,12 +6,12 @@ import { Card } from "@/components/ui/card";
import { Pagination } from "@/components/ui/pagination";
import { QSP } from "@/config/qsp";
import useQuery from "@/hooks/useQuery";
+import { RESOURCE_POOL_ALLOCATED_KIND } from "@/screens/resource-manager/constants";
+import { GET_RESOURCE_POOL_ALLOCATED } from "@/screens/resource-manager/graphql/resource-pool";
import { constructPath } from "@/utils/fetch";
import { getObjectDetailsUrl2 } from "@/utils/objects";
import { Icon } from "@iconify-icon/react";
import { Link, useParams } from "react-router-dom";
-import { RESOURCE_POOL_ALLOCATED_KIND } from "@/screens/resource-manager/constants";
-import { GET_RESOURCE_POOL_ALLOCATED } from "@/screens/resource-manager/graphql/resource-pool";
const ResourceAllocationDetailsPage = () => {
const { resourcePoolId, resourceId } = useParams();
diff --git a/frontend/app/src/pages/resource-manager/resource-pool-details.tsx b/frontend/app/src/pages/resource-manager/resource-pool-details.tsx
index 892cb4cea1..30a3e3e778 100644
--- a/frontend/app/src/pages/resource-manager/resource-pool-details.tsx
+++ b/frontend/app/src/pages/resource-manager/resource-pool-details.tsx
@@ -4,15 +4,22 @@ import { Property, PropertyList } from "@/components/table/property-list";
import { Badge } from "@/components/ui/badge";
import { CardWithBorder } from "@/components/ui/card";
import { Link } from "@/components/ui/link";
+import { useObjectDetails } from "@/hooks/useObjectDetails";
import ErrorScreen from "@/screens/errors/error-screen";
import NoDataFound from "@/screens/errors/no-data-found";
import { IP_SUMMARY_RELATIONSHIPS_BLACKLIST } from "@/screens/ipam/constants";
import Content from "@/screens/layout/content";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import ResourcePoolUtilization from "@/screens/resource-manager/common/ResourcePoolUtilization";
+import {
+ RESOURCE_GENERIC_KIND,
+ RESOURCE_POOL_UTILIZATION_KIND,
+} from "@/screens/resource-manager/constants";
import {
GET_KIND_FOR_RESOURCE_POOL,
GET_RESOURCE_POOL_UTILIZATION,
} from "@/screens/resource-manager/graphql/resource-pool";
+import ResourceSelector, { ResourceProps } from "@/screens/resource-manager/resource-selector";
import { iNodeSchema, schemaState } from "@/state/atoms/schema.atom";
import { constructPath } from "@/utils/fetch";
import { ObjectAttributeValue } from "@/utils/getObjectItemDisplayValue";
@@ -21,13 +28,6 @@ import { useQuery } from "@apollo/client";
import { Icon } from "@iconify-icon/react";
import { useAtomValue } from "jotai";
import { Outlet, useParams } from "react-router-dom";
-import ResourcePoolUtilization from "@/screens/resource-manager/common/ResourcePoolUtilization";
-import {
- RESOURCE_GENERIC_KIND,
- RESOURCE_POOL_UTILIZATION_KIND,
-} from "@/screens/resource-manager/constants";
-import ResourceSelector, { ResourceProps } from "@/screens/resource-manager/resource-selector";
-import { useObjectDetails } from "@/hooks/useObjectDetails";
const ResourcePoolDetailsPage = () => {
const { resourcePoolId } = useParams();
@@ -108,7 +108,8 @@ const ResourcePoolContent = ({ id, schema }: ResourcePoolContentProps) => {
+ )}
+ >
{relationshipData?.display_label}
),
@@ -125,7 +126,8 @@ const ResourcePoolContent = ({ id, schema }: ResourcePoolContentProps) => {
{resourcePoolData.node.display_label}
- }>
+ }
+ >
+
+
+
+
+
+
+
+
+ );
+}
+
+export function Component() {
+ return ;
+}
diff --git a/frontend/app/src/pages/schema.tsx b/frontend/app/src/pages/schema.tsx
index 845b98cd6b..4e9bcec0cf 100644
--- a/frontend/app/src/pages/schema.tsx
+++ b/frontend/app/src/pages/schema.tsx
@@ -1,10 +1,10 @@
-import { useAtomValue } from "jotai";
import { Badge } from "@/components/ui/badge";
import { useTitle } from "@/hooks/useTitle";
-import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
import Content from "@/screens/layout/content";
import { SchemaSelector } from "@/screens/schema/schema-selector";
import { SchemaViewerStack } from "@/screens/schema/schema-viewer";
+import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
+import { useAtomValue } from "jotai";
function SchemaPage() {
useTitle("Schema");
diff --git a/frontend/app/src/pages/sign-in.tsx b/frontend/app/src/pages/sign-in.tsx
index a1bf31a6fd..9eb452f5a9 100644
--- a/frontend/app/src/pages/sign-in.tsx
+++ b/frontend/app/src/pages/sign-in.tsx
@@ -1,14 +1,19 @@
import { Card } from "@/components/ui/card";
import { useAuth } from "@/hooks/useAuth";
import { ReactComponent as InfrahubLogo } from "@/images/Infrahub-SVG-verti.svg";
+import { SignIn } from "@/screens/authentification/sign-in";
import Content from "@/screens/layout/content";
-import { Navigate, useLocation, useNavigate } from "react-router-dom";
-import InputField from "@/components/form/fields/input.field";
-import { isRequired } from "@/components/form/utils/validation";
-import PasswordInputField from "@/components/form/fields/password-input.field";
-import { Form, FormSubmit } from "@/components/ui/form";
+import { Navigate, useLocation } from "react-router-dom";
function SignInPage() {
+ let location = useLocation();
+ const { isAuthenticated } = useAuth();
+
+ if (isAuthenticated) {
+ const from = (location.state?.from?.pathname || "/") + (location.state?.from?.search ?? "");
+ return ;
+ }
+
return (
@@ -17,49 +22,19 @@ function SignInPage() {
Sign in to your account
-
+
+
+ {location?.state?.errors?.map(
+ (error: { extensions: { code: number }; message: string }, index: number) => (
+
+ ({error.extensions.code}) {error.message}
+
+ )
+ )}
);
}
-const SignInForm = () => {
- let navigate = useNavigate();
- let location = useLocation();
- const { signIn } = useAuth();
-
- const from = (location.state?.from?.pathname || "/") + (location.state?.from?.search ?? "");
-
- return (
-
- );
-};
-
-export function Component() {
- const { isAuthenticated } = useAuth();
-
- if (isAuthenticated) {
- return
;
- }
-
- return
;
-}
+export const Component = SignInPage;
diff --git a/frontend/app/src/pages/tasks/index.tsx b/frontend/app/src/pages/tasks/index.tsx
index 47d6babb84..a00c448a41 100644
--- a/frontend/app/src/pages/tasks/index.tsx
+++ b/frontend/app/src/pages/tasks/index.tsx
@@ -6,8 +6,8 @@ import { useTitle } from "@/hooks/useTitle";
import ErrorScreen from "@/screens/errors/error-screen";
import Content from "@/screens/layout/content";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
-import { gql } from "@apollo/client";
import { TaskItems } from "@/screens/tasks/task-items";
+import { gql } from "@apollo/client";
const TasksPage = () => {
useTitle("Task Overview");
@@ -30,7 +30,7 @@ const TasksPage = () => {
return
;
}
- const result = data ? data[TASK_OBJECT] ?? {} : {};
+ const result = data ? (data[TASK_OBJECT] ?? {}) : {};
const { count } = result;
diff --git a/frontend/app/src/pages/tasks/task-details.tsx b/frontend/app/src/pages/tasks/task-details.tsx
index 8e429c1393..593fef6e04 100644
--- a/frontend/app/src/pages/tasks/task-details.tsx
+++ b/frontend/app/src/pages/tasks/task-details.tsx
@@ -37,7 +37,7 @@ const TaskDetailsPage = () => {
return
;
}
- const result = data ? data[TASK_OBJECT] ?? {} : {};
+ const result = data ? (data[TASK_OBJECT] ?? {}) : {};
const { edges = [] } = result;
diff --git a/frontend/app/src/reportWebVitals.ts b/frontend/app/src/reportWebVitals.ts
deleted file mode 100644
index 5fa3583b75..0000000000
--- a/frontend/app/src/reportWebVitals.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { ReportHandler } from "web-vitals";
-
-const reportWebVitals = (onPerfEntry?: ReportHandler) => {
- if (onPerfEntry && onPerfEntry instanceof Function) {
- import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
- getCLS(onPerfEntry);
- getFID(onPerfEntry);
- getFCP(onPerfEntry);
- getLCP(onPerfEntry);
- getTTFB(onPerfEntry);
- });
- }
-};
-
-export default reportWebVitals;
diff --git a/frontend/app/src/router.tsx b/frontend/app/src/router.tsx
index 6074bac4a3..b81f79a085 100644
--- a/frontend/app/src/router.tsx
+++ b/frontend/app/src/router.tsx
@@ -1,164 +1,478 @@
-import { createBrowserRouter, Navigate, Outlet } from "react-router-dom";
-import { IPAM_ROUTE } from "@/screens/ipam/constants";
-import { ARTIFACT_OBJECT, GRAPHQL_QUERY_OBJECT } from "@/config/constants";
import { Root } from "@/Root";
-import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6";
-import queryString from "query-string";
+import {
+ ARTIFACT_OBJECT,
+ GRAPHQL_QUERY_OBJECT,
+ NODE_OBJECT,
+ PROPOSED_CHANGES_OBJECT,
+} from "@/config/constants";
import { RequireAuth } from "@/hooks/useAuth";
+import { constructPathForIpam } from "@/screens/ipam/common/utils";
+import { IPAM_ROUTE, IP_ADDRESS_GENERIC, IP_PREFIX_GENERIC } from "@/screens/ipam/constants";
+import { RESOURCE_GENERIC_KIND } from "@/screens/resource-manager/constants";
+import { constructPath } from "@/utils/fetch";
+import queryString from "query-string";
+import { Navigate, Outlet, UIMatch, createBrowserRouter } from "react-router-dom";
import { QueryParamProvider } from "use-query-params";
+import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6";
export const router = createBrowserRouter([
{
path: "",
element: (
-
-
-
-
-
-
-
+
+
+
+
+
),
children: [
{
- path: "/",
- lazy: () => import("@/screens/layout/layout"),
+ path: "",
+ element: (
+
+
+
+ ),
children: [
{
- path: "/branches/*",
- lazy: () => import("@/pages/branches/details"),
- },
- {
- path: "/branches",
- lazy: () => import("@/pages/branches"),
- },
- {
- path: `/objects/${ARTIFACT_OBJECT}/:objectid`,
- lazy: () => import("@/pages/objects/CoreArtifact/artifact-details"),
- },
- {
- path: `/objects/${GRAPHQL_QUERY_OBJECT}/:graphqlQueryId`,
- lazy: () => import("@/pages/objects/CoreGraphQLQuery/graphql-query-details"),
- },
- {
- path: "/objects",
- lazy: () => import("@/pages/objects/layout"),
+ path: "/",
+ lazy: () => import("@/screens/layout/layout"),
children: [
{
- path: ":objectKind",
- lazy: () => import("@/pages/objects/object-items"),
+ index: true,
+ lazy: () => import("@/pages/homepage"),
},
{
- path: ":objectKind/:objectid",
- lazy: () => import("@/pages/objects/object-details"),
+ path: "/branches",
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Branches",
+ to: constructPath("/branches"),
+ };
+ },
+ },
+ children: [
+ {
+ index: true,
+ lazy: () => import("@/pages/branches"),
+ },
+ {
+ path: "*",
+ lazy: () => import("@/pages/branches/details"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "branch",
+ value: match.params["*"],
+ };
+ },
+ },
+ },
+ ],
},
- ],
- },
- {
- path: "/profile",
- lazy: () => import("@/pages/profile"),
- },
- {
- path: "/proposed-changes/new",
- lazy: () => import("@/pages/proposed-changes/new"),
- },
- {
- path: "/proposed-changes/:proposedChangeId",
- lazy: () => import("@/pages/proposed-changes/details"),
- },
- {
- path: "/proposed-changes",
- lazy: () => import("@/pages/proposed-changes/items"),
- },
- {
- path: "/tasks/:task",
- lazy: () => import("@/pages/tasks/task-details"),
- },
- {
- path: "/tasks",
- lazy: () => import("@/pages/tasks"),
- },
- {
- path: "/graphql/:branch",
- lazy: () => import("@/pages/graphql/redirect-to-graphql-sandbox-page"),
- },
- {
- path: "graphql",
- lazy: () => import("@/pages/graphql"),
- },
- {
- path: "/resource-manager",
- lazy: () => import("@/pages/resource-manager"),
- },
- {
- path: "/resource-manager/:resourcePoolId",
- lazy: () => import("@/pages/resource-manager/resource-pool-details"),
- children: [
{
- path: "resources/:resourceId",
- lazy: () => import("@/pages/resource-manager/resource-allocation-details"),
+ path: `/objects/${ARTIFACT_OBJECT}/:objectid`,
+ lazy: () => import("@/pages/objects/CoreArtifact/artifact-details"),
},
- ],
- },
- {
- path: "/schema",
- lazy: () => import("@/pages/schema"),
- },
- {
- path: IPAM_ROUTE.INDEX,
- lazy: () => import("@/pages/ipam/layout"),
- children: [
{
- index: true,
- lazy: () => import("@/screens/ipam/ipam-router"),
+ path: `/objects/${GRAPHQL_QUERY_OBJECT}/:graphqlQueryId`,
+ lazy: () => import("@/pages/objects/CoreGraphQLQuery/graphql-query-details"),
},
{
- path: IPAM_ROUTE.ADDRESSES,
- lazy: () => import("@/screens/ipam/ipam-router"),
+ path: "/objects",
+ lazy: () => import("@/pages/objects/layout"),
children: [
{
- path: ":ip_address",
- lazy: () => import("@/screens/ipam/ipam-router"),
+ path: ":objectKind",
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.objectKind,
+ kind: "schema",
+ };
+ },
+ },
+ children: [
+ {
+ index: true,
+ lazy: () => import("@/pages/objects/object-items"),
+ },
+ {
+ path: ":objectid",
+ lazy: () => import("@/pages/objects/object-details"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.objectid,
+ kind: match.params.objectKind,
+ };
+ },
+ },
+ },
+ ],
},
],
},
{
- path: IPAM_ROUTE.PREFIXES,
- lazy: () => import("@/screens/ipam/ipam-router"),
+ path: "/profile",
+ lazy: () => import("@/pages/profile"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Account settings",
+ to: constructPath("/profile"),
+ };
+ },
+ },
+ },
+ {
+ path: "/proposed-changes",
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Proposed changes",
+ to: constructPath("/proposed-changes"),
+ };
+ },
+ },
children: [
{
- path: ":prefix",
+ index: true,
+ lazy: () => import("@/pages/proposed-changes/items"),
+ },
+ {
+ path: "new",
+ lazy: () => import("@/pages/proposed-changes/new"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "new",
+ to: constructPath("/proposed-changes/new"),
+ };
+ },
+ },
+ },
+ {
+ path: ":proposedChangeId",
+ lazy: () => import("@/pages/proposed-changes/details"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.proposedChangeId,
+ kind: PROPOSED_CHANGES_OBJECT,
+ };
+ },
+ },
+ },
+ ],
+ },
+ {
+ path: "/tasks",
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Tasks",
+ to: constructPath("/tasks"),
+ };
+ },
+ },
+ children: [
+ {
+ index: true,
+ lazy: () => import("@/pages/tasks"),
+ },
+ {
+ path: ":task",
+ lazy: () => import("@/pages/tasks/task-details"),
+ },
+ ],
+ },
+ {
+ path: "graphql",
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "GraphQL Sandbox",
+ to: constructPath("/graphql"),
+ };
+ },
+ },
+ children: [
+ {
+ index: true,
+ lazy: () => import("@/pages/graphql"),
+ },
+ {
+ path: ":branch",
+ lazy: () => import("@/pages/graphql/redirect-to-graphql-sandbox-page"),
+ },
+ ],
+ },
+ {
+ path: "/resource-manager",
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Resource manager",
+ to: constructPath("/resource-manager"),
+ };
+ },
+ },
+ children: [
+ {
+ index: true,
+ lazy: () => import("@/pages/resource-manager"),
+ },
+ {
+ path: ":resourcePoolId",
+ lazy: () => import("@/pages/resource-manager/resource-pool-details"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.resourcePoolId,
+ kind: RESOURCE_GENERIC_KIND,
+ };
+ },
+ },
+ children: [
+ {
+ path: "resources/:resourceId",
+ lazy: () => import("@/pages/resource-manager/resource-allocation-details"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.resourceId,
+ kind: NODE_OBJECT,
+ };
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+ {
+ path: "/schema",
+ lazy: () => import("@/pages/schema"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Schema",
+ to: constructPath("/schema"),
+ };
+ },
+ },
+ },
+ {
+ path: IPAM_ROUTE.INDEX,
+ lazy: () => import("@/pages/ipam/layout"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "IP Address Manager",
+ to: constructPathForIpam("/ipam"),
+ };
+ },
+ },
+ children: [
+ {
+ index: true,
lazy: () => import("@/screens/ipam/ipam-router"),
+ },
+ {
+ path: IPAM_ROUTE.ADDRESSES,
+ lazy: () => import("@/screens/ipam/ipam-router"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "IP Addresses",
+ to: constructPathForIpam("/ipam/addresses"),
+ };
+ },
+ },
children: [
{
path: ":ip_address",
lazy: () => import("@/screens/ipam/ipam-router"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.ip_address,
+ kind: IP_ADDRESS_GENERIC,
+ };
+ },
+ },
+ },
+ ],
+ },
+ {
+ path: IPAM_ROUTE.PREFIXES,
+ lazy: () => import("@/screens/ipam/ipam-router"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "IP Prefixes",
+ to: constructPathForIpam("/ipam/prefixes"),
+ };
+ },
+ },
+ children: [
+ {
+ path: ":prefix",
+ lazy: () => import("@/screens/ipam/ipam-router"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.prefix,
+ kind: IP_PREFIX_GENERIC,
+ };
+ },
+ },
+ children: [
+ {
+ path: ":ip_address",
+ lazy: () => import("@/screens/ipam/ipam-router"),
+ handle: {
+ breadcrumb: (match: UIMatch) => {
+ return {
+ type: "select",
+ value: match.params.ip_address,
+ kind: IP_ADDRESS_GENERIC,
+ };
+ },
+ },
+ },
+ ],
},
],
},
],
},
+ {
+ path: "role-management",
+ lazy: () => import("@/pages/role-management"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Role Management",
+ to: constructPath("/role-management"),
+ };
+ },
+ },
+ children: [
+ {
+ index: true,
+ lazy: () => import("@/screens/role-management/accounts"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Accounts",
+ to: constructPath("/role-management/accounts"),
+ };
+ },
+ },
+ },
+ {
+ path: "groups",
+ lazy: () => import("@/screens/role-management/groups"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Groups",
+ to: constructPath("/role-management/groups"),
+ };
+ },
+ },
+ },
+ {
+ path: "roles",
+ lazy: () => import("@/screens/role-management/roles"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Roles",
+ to: constructPath("/role-management/roles"),
+ };
+ },
+ },
+ },
+ {
+ path: "global-permissions",
+ lazy: () => import("@/screens/role-management/global-permissions"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Global Permissions",
+ to: constructPath("/role-management/global-permissions"),
+ };
+ },
+ },
+ },
+ {
+ path: "object-permissions",
+ lazy: () => import("@/screens/role-management/object-permissions"),
+ handle: {
+ breadcrumb: () => {
+ return {
+ type: "link",
+ label: "Object Permissions",
+ to: constructPath("/role-management/object-permissions"),
+ };
+ },
+ },
+ },
+ ],
+ },
+ {
+ path: "*",
+ element:
,
+ },
],
},
- {
- path: "/",
- lazy: () => import("@/pages/homepage"),
- },
{
path: "*",
element:
,
},
],
},
+ {
+ path: "/signin",
+ lazy: () => import("@/pages/sign-in"),
+ },
+ {
+ path: "auth/:protocol/:provider/callback",
+ lazy: () => import("@/pages/auth-callback"),
+ },
],
},
- {
- path: "/signin",
- lazy: () => import("@/pages/sign-in"),
- },
]);
diff --git a/frontend/app/src/screens/artifacts/generate.tsx b/frontend/app/src/screens/artifacts/generate.tsx
index 12af7908cd..69e59a49a9 100644
--- a/frontend/app/src/screens/artifacts/generate.tsx
+++ b/frontend/app/src/screens/artifacts/generate.tsx
@@ -68,7 +68,8 @@ export const Generate = (props: tGenerateProps) => {
disabled={!auth?.permissions?.write || isLoading}
onClick={handleGenerate}
className="mr-4"
- buttonType={BUTTON_TYPES.VALIDATE}>
+ buttonType={BUTTON_TYPES.VALIDATE}
+ >
{label ?? "Generate"}
+ variant="outline"
+ >
Manage groups
@@ -174,7 +175,8 @@ export default function ArtifactsDetails() {
href={CONFIG.ARTIFACT_DETAILS_URL(objectDetailsData.id)}
target="_blank"
rel="noreferrer"
- className="cursor-pointer underline">
+ className="cursor-pointer underline"
+ >
{objectDetailsData.id}
@@ -199,7 +201,8 @@ export default function ArtifactsDetails() {
className={classNames(
"text-sm text-gray-900 "
// attribute.kind === "TextArea" ? "whitespace-pre-wrap mr-2" : ""
- )}>
+ )}
+ >
{attribute.name === "storage_id" &&
objectDetailsData[attribute.name]?.value && (
+ className="cursor-pointer underline"
+ >
{objectDetailsData[attribute.name].value}
)}
@@ -240,7 +244,8 @@ export default function ArtifactsDetails() {
});
setShowMetaEditModal(true);
}}
- data-cy="metadata-edit-button">
+ data-cy="metadata-edit-button"
+ >
@@ -294,7 +299,8 @@ export default function ArtifactsDetails() {
/>
}
open={showMetaEditModal}
- setOpen={setShowMetaEditModal}>
+ setOpen={setShowMetaEditModal}
+ >
setShowMetaEditModal(false)}
onUpdateComplete={() => refetch()}
diff --git a/frontend/app/src/screens/authentification/sign-in-sso-buttons.tsx b/frontend/app/src/screens/authentification/sign-in-sso-buttons.tsx
new file mode 100644
index 0000000000..82b990b666
--- /dev/null
+++ b/frontend/app/src/screens/authentification/sign-in-sso-buttons.tsx
@@ -0,0 +1,37 @@
+import { INFRAHUB_API_SERVER_URL } from "@/config/config";
+import { Provider } from "@/state/atoms/config.atom";
+import { Icon } from "@iconify-icon/react";
+import { useLocation } from "react-router-dom";
+
+export const SignInWithSSOButtons = ({ providers }: { providers: Array }) => {
+ let location = useLocation();
+ const redirectTo: string =
+ (location.state?.from?.pathname || "/") + (location.state?.from?.search ?? "");
+
+ return (
+
+ {providers.map((provider) => (
+
+ ))}
+
+ );
+};
+
+export const ProviderButton = ({
+ provider,
+ redirectTo = "/",
+}: { provider: Provider; redirectTo?: string }) => {
+ return (
+
+
+ Sign in with {provider.display_label}
+
+ );
+};
diff --git a/frontend/app/src/screens/authentification/sign-in.tsx b/frontend/app/src/screens/authentification/sign-in.tsx
new file mode 100644
index 0000000000..056b31de70
--- /dev/null
+++ b/frontend/app/src/screens/authentification/sign-in.tsx
@@ -0,0 +1,52 @@
+import InputField from "@/components/form/fields/input.field";
+import PasswordInputField from "@/components/form/fields/password-input.field";
+import { isRequired } from "@/components/form/utils/validation";
+import { Divider } from "@/components/ui/divider";
+import { Form, FormSubmit } from "@/components/ui/form";
+import { useAuth } from "@/hooks/useAuth";
+import { SignInWithSSOButtons } from "@/screens/authentification/sign-in-sso-buttons";
+import { configState } from "@/state/atoms/config.atom";
+import { useAtomValue } from "jotai/index";
+
+export const SignIn = () => {
+ const config = useAtomValue(configState);
+
+ if (config && config.sso.enabled && config.sso.providers.length > 0) {
+ return (
+ <>
+
+ Or
+
+ >
+ );
+ }
+
+ return ;
+};
+
+export const SignInForm = () => {
+ const { signIn } = useAuth();
+
+ return (
+
+ );
+};
diff --git a/frontend/app/src/screens/branches/branch-details.tsx b/frontend/app/src/screens/branches/branch-details.tsx
index 1c1c3305d4..4616e6a68b 100644
--- a/frontend/app/src/screens/branches/branch-details.tsx
+++ b/frontend/app/src/screens/branches/branch-details.tsx
@@ -2,6 +2,7 @@ import { BUTTON_TYPES, Button } from "@/components/buttons/button";
import { Badge } from "@/components/display/badge";
import { DateDisplay } from "@/components/display/date-display";
import SlideOver from "@/components/display/slide-over";
+import ObjectForm from "@/components/form/object-form";
import ModalDelete from "@/components/modals/modal-delete";
import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { PROPOSED_CHANGES_OBJECT } from "@/config/constants";
@@ -11,11 +12,12 @@ import { deleteBranch } from "@/graphql/mutations/branches/deleteBranch";
import { mergeBranch } from "@/graphql/mutations/branches/mergeBranch";
import { rebaseBranch } from "@/graphql/mutations/branches/rebaseBranch";
import { validateBranch } from "@/graphql/mutations/branches/validateBranch";
+import { getBranchDetailsQuery } from "@/graphql/queries/branches/getBranchDetails";
import { useAuth } from "@/hooks/useAuth";
import useQuery from "@/hooks/useQuery";
import ErrorScreen from "@/screens/errors/error-screen";
+import NoDataFound from "@/screens/errors/no-data-found";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
-import ObjectForm from "@/components/form/object-form";
import { branchesState } from "@/state/atoms/branches.atom";
import { datetimeAtom } from "@/state/atoms/time.atom";
import { objectToString } from "@/utils/common";
@@ -29,8 +31,6 @@ import { useAtomValue } from "jotai/index";
import { useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
-import { getBranchDetailsQuery } from "@/graphql/queries/branches/getBranchDetails";
-import NoDataFound from "@/screens/errors/no-data-found";
export const BranchDetails = () => {
const { "*": branchName } = useParams();
@@ -184,7 +184,8 @@ export const BranchDetails = () => {
},
})
}
- buttonType={BUTTON_TYPES.VALIDATE}>
+ buttonType={BUTTON_TYPES.VALIDATE}
+ >
Merge
@@ -192,7 +193,8 @@ export const BranchDetails = () => {
setShowCreateDrawer(true)}>
+ onClick={() => setShowCreateDrawer(true)}
+ >
Propose change
@@ -209,7 +211,8 @@ export const BranchDetails = () => {
name: branch.name,
},
})
- }>
+ }
+ >
Rebase
@@ -227,7 +230,8 @@ export const BranchDetails = () => {
},
})
}
- buttonType={BUTTON_TYPES.WARNING}>
+ buttonType={BUTTON_TYPES.WARNING}
+ >
Validate
@@ -236,7 +240,8 @@ export const BranchDetails = () => {
disabled={!auth?.permissions?.write || branch.is_default}
className="mr-0 md:mr-3"
onClick={() => setDisplayModal(true)}
- buttonType={BUTTON_TYPES.CANCEL}>
+ buttonType={BUTTON_TYPES.CANCEL}
+ >
Delete
@@ -273,7 +278,8 @@ export const BranchDetails = () => {
{PROPOSED_CHANGES_OBJECT}
@@ -281,7 +287,8 @@ export const BranchDetails = () => {
}
open={showCreateDrawer}
- setOpen={setShowCreateDrawer}>
+ setOpen={setShowCreateDrawer}
+ >
setShowCreateDrawer(false)}
diff --git a/frontend/app/src/screens/branches/branches-items.tsx b/frontend/app/src/screens/branches/branches-items.tsx
index 4978484e57..c1ee6c06ef 100644
--- a/frontend/app/src/screens/branches/branches-items.tsx
+++ b/frontend/app/src/screens/branches/branches-items.tsx
@@ -47,12 +47,14 @@ const BranchesItems = () => {
+ data-testid="branches-items"
+ >
{branches.map((branch) => (
- navigate(constructPath(`/branches/${branch.name}`))}>
+ className="col-span-1 rounded-lg bg-custom-white border cursor-pointer hover:bg-gray-50"
+ onClick={() => navigate(constructPath(`/branches/${branch.name}`))}
+ >
diff --git a/frontend/app/src/screens/branches/diff.tsx b/frontend/app/src/screens/branches/diff.tsx
index 22f422072d..0ad6ad100b 100644
--- a/frontend/app/src/screens/branches/diff.tsx
+++ b/frontend/app/src/screens/branches/diff.tsx
@@ -1,12 +1,12 @@
+import DatetimeField from "@/components/form/fields/datetime.field";
import { Tabs } from "@/components/tabs";
+import { Form, FormSubmit } from "@/components/ui/form";
+import { DIFF_TABS } from "@/config/constants";
import { QSP } from "@/config/qsp";
import { DateTimeParam, StringParam, useQueryParam } from "use-query-params";
import { ArtifactsDiff } from "../diff/artifact-diff/artifacts-diff";
-import { NodeDiff } from "../diff/node-diff";
import { FilesDiff } from "../diff/file-diff/files-diff";
-import { Form, FormSubmit } from "@/components/ui/form";
-import DatetimeField from "@/components/form/fields/datetime.field";
-import { DIFF_TABS } from "@/config/constants";
+import { NodeDiff } from "../diff/node-diff";
const tabs = [
{
diff --git a/frontend/app/src/screens/diff/artifact-diff/artifact-content-diff.tsx b/frontend/app/src/screens/diff/artifact-diff/artifact-content-diff.tsx
index 9d3be72cb0..b68f007b40 100644
--- a/frontend/app/src/screens/diff/artifact-diff/artifact-content-diff.tsx
+++ b/frontend/app/src/screens/diff/artifact-diff/artifact-content-diff.tsx
@@ -325,7 +325,8 @@ export const ArtifactContentDiff = (props: any) => {
[changeKey]: change?.comments?.map((comment: any, index: number) => (
+ className="bg-custom-white p-4 border border-custom-blue-500 rounded-md m-2"
+ >
{comment.message}
)),
@@ -359,7 +360,8 @@ export const ArtifactContentDiff = (props: any) => {
{inHoverState && (
+ onClick={handleClick}
+ >
)}
@@ -413,7 +415,8 @@ export const ArtifactContentDiff = (props: any) => {
diffType={fileContent.type}
renderGutter={renderGutter}
widgets={getWidgets(fileContent.hunks)}
- optimizeSelection>
+ optimizeSelection
+ >
{(hunks) => hunks.map((hunk) =>
)}
diff --git a/frontend/app/src/screens/diff/artifact-diff/artifact-repo-diff.tsx b/frontend/app/src/screens/diff/artifact-diff/artifact-repo-diff.tsx
index 5dacc62772..0eb0408d10 100644
--- a/frontend/app/src/screens/diff/artifact-diff/artifact-repo-diff.tsx
+++ b/frontend/app/src/screens/diff/artifact-diff/artifact-repo-diff.tsx
@@ -3,8 +3,8 @@ import { Badge } from "@/components/display/badge";
import { getArtifactDetails } from "@/graphql/queries/getArtifacts";
import useQuery from "@/hooks/useQuery";
import ErrorScreen from "@/screens/errors/error-screen";
-import LoadingScreen from "@/screens/loading-screen/loading-screen";
import NoDataFound from "@/screens/errors/no-data-found";
+import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { schemaState } from "@/state/atoms/schema.atom";
import { gql } from "@apollo/client";
import { useAtom } from "jotai";
diff --git a/frontend/app/src/screens/diff/checks/check.tsx b/frontend/app/src/screens/diff/checks/check.tsx
index 6bd4ac524a..25f92a94e9 100644
--- a/frontend/app/src/screens/diff/checks/check.tsx
+++ b/frontend/app/src/screens/diff/checks/check.tsx
@@ -150,7 +150,8 @@ export const Check = ({ id }: tCheckProps) => {
className={classNames(
"flex flex-col rounded-md p-2 bg-gray-50 border border-l-4",
getCheckBorderColor(severity?.value)
- )}>
+ )}
+ >
diff --git a/frontend/app/src/screens/diff/checks/conflict.tsx b/frontend/app/src/screens/diff/checks/conflict.tsx
index 4969b7d469..0c0da0dfee 100644
--- a/frontend/app/src/screens/diff/checks/conflict.tsx
+++ b/frontend/app/src/screens/diff/checks/conflict.tsx
@@ -149,7 +149,8 @@ export const Conflict = (props: any) => {
return (
+ className={classNames("flex-1 grid grid-cols-2 gap-2 p-2 rounded-md", className)}
+ >
{branch}
diff --git a/frontend/app/src/screens/diff/checks/validator-checks-progress.tsx b/frontend/app/src/screens/diff/checks/validator-checks-progress.tsx
index f8a0853ddc..f6727da699 100644
--- a/frontend/app/src/screens/diff/checks/validator-checks-progress.tsx
+++ b/frontend/app/src/screens/diff/checks/validator-checks-progress.tsx
@@ -16,7 +16,8 @@ const getCheckBar = (type: string, amount: number, total: number, index: number)
+ style={{ width: `${precentage}%` }}
+ >
{amount}
);
@@ -26,7 +27,8 @@ const getCheckBar = (type: string, amount: number, total: number, index: number)
+ style={{ width: `${precentage}%` }}
+ >
{amount}
);
@@ -36,7 +38,8 @@ const getCheckBar = (type: string, amount: number, total: number, index: number)
+ style={{ width: `${precentage}%` }}
+ >
{amount}
);
@@ -46,7 +49,8 @@ const getCheckBar = (type: string, amount: number, total: number, index: number)
+ style={{ width: `${precentage}%` }}
+ >
{amount}
);
@@ -56,7 +60,8 @@ const getCheckBar = (type: string, amount: number, total: number, index: number)
+ style={{ width: `${precentage}%` }}
+ >
{amount}
);
@@ -66,7 +71,8 @@ const getCheckBar = (type: string, amount: number, total: number, index: number)
+ style={{ width: `${precentage}%` }}
+ >
{amount}
);
diff --git a/frontend/app/src/screens/diff/diff-badge.tsx b/frontend/app/src/screens/diff/diff-badge.tsx
index 9b6d890329..8b45446b0d 100644
--- a/frontend/app/src/screens/diff/diff-badge.tsx
+++ b/frontend/app/src/screens/diff/diff-badge.tsx
@@ -33,7 +33,8 @@ export const BadgeUnchanged = ({
hasConflicts && "border-none p-0 pl-1 gap-1",
className
)}
- {...props}>
+ {...props}
+ >
{(children || children === 0) &&
{children}}
{hasConflicts &&
}
@@ -103,7 +104,8 @@ const CloseBadge = ({ className }: CloseBadgeProps) => {
className={classNames(
"flex justify-center items-center absolute border-2 border-white -top-2 -right-2 rounded-full",
className
- )}>
+ )}
+ >
);
diff --git a/frontend/app/src/screens/diff/diff-tree.tsx b/frontend/app/src/screens/diff/diff-tree.tsx
index 9ce8d1c36e..837c94ea6d 100644
--- a/frontend/app/src/screens/diff/diff-tree.tsx
+++ b/frontend/app/src/screens/diff/diff-tree.tsx
@@ -1,13 +1,13 @@
+import { Tooltip } from "@/components/ui/tooltip";
import { Tree, TreeItemProps, TreeProps } from "@/components/ui/tree";
-import { useEffect, useState } from "react";
-import { addItemsToTree, EMPTY_TREE } from "@/screens/ipam/ipam-tree/utils";
-import { DiffBadge } from "@/screens/diff/node-diff/utils";
+import { useSchema } from "@/hooks/useSchema";
import { DiffNode } from "@/screens/diff/node-diff/types";
-import { useLocation, useNavigate } from "react-router-dom";
+import { DiffBadge } from "@/screens/diff/node-diff/utils";
import { TREE_ROOT_ID } from "@/screens/ipam/constants";
-import { useSchema } from "@/hooks/useSchema";
+import { EMPTY_TREE, addItemsToTree } from "@/screens/ipam/ipam-tree/utils";
import { Icon } from "@iconify-icon/react";
-import { Tooltip } from "@/components/ui/tooltip";
+import { useEffect, useState } from "react";
+import { useLocation, useNavigate } from "react-router-dom";
interface DiffTreeProps extends Omit
{
nodes: Array;
@@ -65,7 +65,8 @@ const DiffTreeItem = ({ element }: TreeItemProps) => {
href={"#" + diffNode?.uuid}
tabIndex={-1}
className="flex items-center gap-2 text-gray-800 overflow-hidden"
- data-testid="hierarchical-tree-item">
+ data-testid="hierarchical-tree-item"
+ >
{
};
export const formatDiffNodesToDiffTree = (nodes: Array) => {
- return nodes.reduce((acc, node) => {
- const newNode = {
- id: node.uuid,
- name: node.label,
- parent: TREE_ROOT_ID as string,
- children: acc.filter(({ parent }) => parent === node.uuid).map(({ id }) => id),
- metadata: {
- kind: node.kind, // for icon on tree item
- uuid: node.uuid, // for url
- status: node.status, // for icon color
- containsConflicts: node.contains_conflict, // for icon conflicts
- },
- };
-
- if (node.parent) {
- const { uuid: parentUUID, relationship_name: parentRelationshipName } = node.parent;
-
- const parentNodeId = parentUUID + parentRelationshipName;
- const newNodeWithParent = {
- ...newNode,
- parent: parentNodeId,
+ return nodes.reduce(
+ (acc, node) => {
+ const newNode = {
+ id: node.uuid,
+ name: node.label,
+ parent: TREE_ROOT_ID as string,
+ children: acc.filter(({ parent }) => parent === node.uuid).map(({ id }) => id),
+ metadata: {
+ kind: node.kind, // for icon on tree item
+ uuid: node.uuid, // for url
+ status: node.status, // for icon color
+ containsConflicts: node.contains_conflict, // for icon conflicts
+ },
};
- const existingParentOfNewNode = acc.find(({ id }) => id === parentNodeId);
- if (existingParentOfNewNode) {
+ if (node.parent) {
+ const { uuid: parentUUID, relationship_name: parentRelationshipName } = node.parent;
+
+ const parentNodeId = parentUUID + parentRelationshipName;
+ const newNodeWithParent = {
+ ...newNode,
+ parent: parentNodeId,
+ };
+
+ const existingParentOfNewNode = acc.find(({ id }) => id === parentNodeId);
+ if (existingParentOfNewNode) {
+ return acc
+ .map((accNode) => {
+ if (accNode.id === parentNodeId) {
+ return {
+ ...accNode,
+ children: [...new Set(accNode.children.concat(newNodeWithParent.id))],
+ };
+ }
+
+ return accNode;
+ })
+ .concat(newNodeWithParent);
+ }
+
+ const newParentNode = {
+ id: parentNodeId,
+ name: parentRelationshipName ?? "",
+ parent: parentUUID,
+ children: [newNode.id],
+ metadata: {
+ kind: node.parent.kind, // for icon on tree item
+ },
+ };
+
return acc
.map((accNode) => {
- if (accNode.id === parentNodeId) {
+ if (accNode.id === parentUUID) {
return {
...accNode,
- children: [...new Set(accNode.children.concat(newNodeWithParent.id))],
+ children: [...new Set(accNode.children.concat(newParentNode.id))],
};
}
return accNode;
})
- .concat(newNodeWithParent);
+ .concat(newParentNode, newNodeWithParent);
}
- const newParentNode = {
- id: parentNodeId,
- name: parentRelationshipName ?? "",
- parent: parentUUID,
- children: [newNode.id],
- metadata: {
- kind: node.parent.kind, // for icon on tree item
- },
- };
-
- return acc
- .map((accNode) => {
- if (accNode.id === parentUUID) {
- return {
- ...accNode,
- children: [...new Set(accNode.children.concat(newParentNode.id))],
- };
- }
-
- return accNode;
- })
- .concat(newParentNode, newNodeWithParent);
- }
-
- return [...acc, newNode];
- }, [] as TreeProps["data"]);
+ return [...acc, newNode];
+ },
+ [] as TreeProps["data"]
+ );
};
export const generateRootCategoryNodeForDiffTree = (
diffTreeNodes: TreeProps["data"]
): TreeProps["data"] => {
- return diffTreeNodes.reduce((acc, node) => {
- const nodeKind = node.metadata?.kind as string | undefined;
- if (node.parent !== TREE_ROOT_ID || !nodeKind) return [...acc, node];
-
- const nodeUpdated = {
- ...node,
- parent: nodeKind,
- };
-
- const existingRootCategoryNode = acc.find(({ id }) => id === nodeKind);
-
- if (existingRootCategoryNode) {
- const rootCategoryNodeUpdated = {
- ...existingRootCategoryNode,
- children: [...existingRootCategoryNode.children, node.id],
+ return diffTreeNodes.reduce(
+ (acc, node) => {
+ const nodeKind = node.metadata?.kind as string | undefined;
+ if (node.parent !== TREE_ROOT_ID || !nodeKind) return [...acc, node];
+
+ const nodeUpdated = {
+ ...node,
+ parent: nodeKind,
};
- return acc
- .map((item) => (item.id === existingRootCategoryNode.id ? rootCategoryNodeUpdated : item))
- .concat(nodeUpdated);
- } else {
- const newRootCategoryNode = {
- id: nodeKind,
- name: nodeKind,
- parent: TREE_ROOT_ID,
- children: [node.id],
- isBranch: true,
- metadata: {
- kind: nodeKind,
- },
- };
+ const existingRootCategoryNode = acc.find(({ id }) => id === nodeKind);
+
+ if (existingRootCategoryNode) {
+ const rootCategoryNodeUpdated = {
+ ...existingRootCategoryNode,
+ children: [...existingRootCategoryNode.children, node.id],
+ };
- return [...acc, newRootCategoryNode, nodeUpdated];
- }
- }, [] as TreeProps["data"]);
+ return acc
+ .map((item) => (item.id === existingRootCategoryNode.id ? rootCategoryNodeUpdated : item))
+ .concat(nodeUpdated);
+ } else {
+ const newRootCategoryNode = {
+ id: nodeKind,
+ name: nodeKind,
+ parent: TREE_ROOT_ID,
+ children: [node.id],
+ isBranch: true,
+ metadata: {
+ kind: nodeKind,
+ },
+ };
+
+ return [...acc, newRootCategoryNode, nodeUpdated];
+ }
+ },
+ [] as TreeProps["data"]
+ );
};
diff --git a/frontend/app/src/screens/diff/file-diff/file-content-diff.tsx b/frontend/app/src/screens/diff/file-diff/file-content-diff.tsx
index 17b0039ded..5219fbbae1 100644
--- a/frontend/app/src/screens/diff/file-diff/file-content-diff.tsx
+++ b/frontend/app/src/screens/diff/file-diff/file-content-diff.tsx
@@ -350,7 +350,8 @@ export const FileContentDiff = (props: any) => {
[changeKey]: change?.comments?.map((comment: any, index: number) => (
+ className="bg-custom-white p-4 border border-custom-blue-500 rounded-md m-2"
+ >
{comment.message}
)),
@@ -379,7 +380,8 @@ export const FileContentDiff = (props: any) => {
{inHoverState && (
+ onClick={handleClick}
+ >
)}
@@ -430,7 +432,8 @@ export const FileContentDiff = (props: any) => {
diffType={fileContent.type}
renderGutter={renderGutter}
widgets={getWidgets(fileContent.hunks)}
- optimizeSelection>
+ optimizeSelection
+ >
{(hunks) => hunks.map((hunk) => )}
diff --git a/frontend/app/src/screens/diff/node-diff/conflict.tsx b/frontend/app/src/screens/diff/node-diff/conflict.tsx
index eb6d944c3f..61a7e4ed87 100644
--- a/frontend/app/src/screens/diff/node-diff/conflict.tsx
+++ b/frontend/app/src/screens/diff/node-diff/conflict.tsx
@@ -74,7 +74,8 @@ export const Conflict = ({ conflict }: any) => {
htmlFor={"base"}
className={
conflict.selected_branch === "BASE_BRANCH" ? "cursor-default" : "cursor-pointer"
- }>
+ }
+ >
{proposedChangesDetails.destination_branch?.value}
@@ -93,7 +94,8 @@ export const Conflict = ({ conflict }: any) => {
htmlFor={"diff"}
className={
conflict.selected_branch === "DIFF_BRANCH" ? "cursor-default" : "cursor-pointer"
- }>
+ }
+ >
{proposedChangesDetails.source_branch?.value}
diff --git a/frontend/app/src/screens/diff/node-diff/index.tsx b/frontend/app/src/screens/diff/node-diff/index.tsx
index 4f12290304..0614031aa6 100644
--- a/frontend/app/src/screens/diff/node-diff/index.tsx
+++ b/frontend/app/src/screens/diff/node-diff/index.tsx
@@ -1,35 +1,35 @@
+import { Button, ButtonProps } from "@/components/buttons/button-primitive";
+import { DateDisplay } from "@/components/display/date-display";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { Badge } from "@/components/ui/badge";
+import { Card } from "@/components/ui/card";
+import { Tooltip } from "@/components/ui/tooltip";
import { PROPOSED_CHANGES_OBJECT_THREAD_OBJECT } from "@/config/constants";
+import { QSP } from "@/config/qsp";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { rebaseBranch } from "@/graphql/mutations/branches/rebaseBranch";
+import { DIFF_UPDATE } from "@/graphql/mutations/proposed-changes/diff/diff-update";
+import { getProposedChangesDiffTree } from "@/graphql/queries/proposed-changes/getProposedChangesDiffTree";
+import { useAuth } from "@/hooks/useAuth";
import useQuery from "@/hooks/useQuery";
+import DiffTree from "@/screens/diff/diff-tree";
+import { DIFF_STATUS, DiffNode as DiffNodeType } from "@/screens/diff/node-diff/types";
+import { DiffBadge } from "@/screens/diff/node-diff/utils";
+import ErrorScreen from "@/screens/errors/error-screen";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { proposedChangedState } from "@/state/atoms/proposedChanges.atom";
import { schemaState } from "@/state/atoms/schema.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
+import { classNames, objectToString } from "@/utils/common";
+import { formatFullDate, formatRelativeTimeFromNow } from "@/utils/date";
+import { NetworkStatus, gql, useMutation } from "@apollo/client";
+import { Icon } from "@iconify-icon/react";
import { useAtomValue } from "jotai";
import { createContext, useState } from "react";
+import { toast } from "react-toastify";
+import { StringParam, useQueryParam } from "use-query-params";
import { DiffFilter, ProposedChangeDiffFilter } from "../../proposed-changes/diff-filter";
-import { getProposedChangesDiffTree } from "@/graphql/queries/proposed-changes/getProposedChangesDiffTree";
import { DiffNode } from "./node";
-import { StringParam, useQueryParam } from "use-query-params";
-import { QSP } from "@/config/qsp";
-import { Card } from "@/components/ui/card";
-import DiffTree from "@/screens/diff/diff-tree";
-import { Button, ButtonProps } from "@/components/buttons/button-primitive";
-import { rebaseBranch } from "@/graphql/mutations/branches/rebaseBranch";
-import { classNames, objectToString } from "@/utils/common";
-import graphqlClient from "@/graphql/graphqlClientApollo";
-import { datetimeAtom } from "@/state/atoms/time.atom";
-import { gql, NetworkStatus, useMutation } from "@apollo/client";
-import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
-import { DIFF_UPDATE } from "@/graphql/mutations/proposed-changes/diff/diff-update";
-import { useAuth } from "@/hooks/useAuth";
-import { DateDisplay } from "@/components/display/date-display";
-import { Icon } from "@iconify-icon/react";
-import { DIFF_STATUS, DiffNode as DiffNodeType } from "@/screens/diff/node-diff/types";
-import { formatFullDate, formatRelativeTimeFromNow } from "@/utils/date";
-import { Tooltip } from "@/components/ui/tooltip";
-import { DiffBadge } from "@/screens/diff/node-diff/utils";
-import { Badge } from "@/components/ui/badge";
-import ErrorScreen from "@/screens/errors/error-screen";
export const DiffContext = createContext({});
@@ -225,7 +225,8 @@ export const NodeDiff = ({ branchName, filters }: NodeDiffProps) => {
size="sm"
variant="primary"
onClick={handleRefresh}
- disabled={!auth?.permissions?.write || isLoadingUpdate}>
+ disabled={!auth?.permissions?.write || isLoadingUpdate}
+ >
Refresh diff
@@ -234,7 +235,8 @@ export const NodeDiff = ({ branchName, filters }: NodeDiffProps) => {
size="sm"
variant="primary-outline"
onClick={handleRebase}
- disabled={isLoadingUpdate}>
+ disabled={isLoadingUpdate}
+ >
Rebase
diff --git a/frontend/app/src/screens/diff/node-diff/node-attribute.tsx b/frontend/app/src/screens/diff/node-diff/node-attribute.tsx
index 2f646e4891..fe16b79bf6 100644
--- a/frontend/app/src/screens/diff/node-diff/node-attribute.tsx
+++ b/frontend/app/src/screens/diff/node-diff/node-attribute.tsx
@@ -1,10 +1,10 @@
-import { useParams } from "react-router-dom";
-import { DiffRow } from "@/screens/diff/node-diff/utils";
-import { DiffAttribute, DiffStatus } from "@/screens/diff/node-diff/types";
-import { DiffThread } from "@/screens/diff/node-diff/thread";
import { DiffNodeProperty } from "@/screens/diff/node-diff/node-property";
-import { Conflict } from "./conflict";
+import { DiffThread } from "@/screens/diff/node-diff/thread";
+import { DiffAttribute, DiffStatus } from "@/screens/diff/node-diff/types";
+import { DiffRow } from "@/screens/diff/node-diff/utils";
+import { useParams } from "react-router-dom";
import { BadgeConflict } from "../diff-badge";
+import { Conflict } from "./conflict";
type DiffNodeAttributeProps = {
attribute: DiffAttribute;
@@ -38,7 +38,8 @@ export const DiffNodeAttribute = ({
}
left={previousValue}
- right={newValue}>
+ right={newValue}
+ >
{attribute.conflict && }
diff --git a/frontend/app/src/screens/diff/node-diff/node-property.tsx b/frontend/app/src/screens/diff/node-diff/node-property.tsx
index f10b7b9f49..b81181307c 100644
--- a/frontend/app/src/screens/diff/node-diff/node-property.tsx
+++ b/frontend/app/src/screens/diff/node-diff/node-property.tsx
@@ -1,12 +1,12 @@
import { Badge } from "@/components/ui/badge";
-import { useParams } from "react-router-dom";
-import { DiffThread } from "./thread";
-import { Icon } from "@iconify-icon/react";
-import { Conflict } from "./conflict";
-import { DiffRow, formatPropertyName, formatValue } from "@/screens/diff/node-diff/utils";
import { BadgeConflict } from "@/screens/diff/diff-badge";
import { DiffProperty, DiffStatus } from "@/screens/diff/node-diff/types";
+import { DiffRow, formatPropertyName, formatValue } from "@/screens/diff/node-diff/utils";
import { classNames } from "@/utils/common";
+import { Icon } from "@iconify-icon/react";
+import { useParams } from "react-router-dom";
+import { Conflict } from "./conflict";
+import { DiffThread } from "./thread";
type DiffNodePropertyProps = {
className?: string;
@@ -77,7 +77,8 @@ export const DiffNodeProperty = ({ status, property, className }: DiffNodeProper
left={getPreviousValue(property)}
leftClassName="font-normal"
rightClassName="font-normal"
- right={getNewValue(property)}>
+ right={getNewValue(property)}
+ >
{property.conflict && }
);
diff --git a/frontend/app/src/screens/diff/node-diff/node-relationship-element.tsx b/frontend/app/src/screens/diff/node-diff/node-relationship-element.tsx
index 62f2b1eb45..6e8cbc5f75 100644
--- a/frontend/app/src/screens/diff/node-diff/node-relationship-element.tsx
+++ b/frontend/app/src/screens/diff/node-diff/node-relationship-element.tsx
@@ -1,9 +1,9 @@
-import { DiffNodeProperty } from "./node-property";
-import { DiffRelationshipElement, DiffStatus } from "@/screens/diff/node-diff/types";
-import { DiffBadge, DiffRow } from "@/screens/diff/node-diff/utils";
import { BadgeConflict } from "@/screens/diff/diff-badge";
import { DiffThread } from "@/screens/diff/node-diff/thread";
+import { DiffRelationshipElement, DiffStatus } from "@/screens/diff/node-diff/types";
+import { DiffBadge, DiffRow } from "@/screens/diff/node-diff/utils";
import { useParams } from "react-router-dom";
+import { DiffNodeProperty } from "./node-property";
type DiffNodeElementProps = {
element: DiffRelationshipElement;
@@ -28,7 +28,8 @@ export const DiffNodeRelationshipElement = ({ element, status }: DiffNodeElement
}
right={element.status === "ADDED" && element.peer_label}
- left={element.status === "REMOVED" && element.peer_label}>
+ left={element.status === "REMOVED" && element.peer_label}
+ >
{element.properties
.filter((property) => property.status !== "UNCHANGED")
diff --git a/frontend/app/src/screens/diff/node-diff/node-relationship.tsx b/frontend/app/src/screens/diff/node-diff/node-relationship.tsx
index 2e65edb536..7b6b983603 100644
--- a/frontend/app/src/screens/diff/node-diff/node-relationship.tsx
+++ b/frontend/app/src/screens/diff/node-diff/node-relationship.tsx
@@ -1,10 +1,10 @@
-import { DiffNodeRelationshipElement } from "./node-relationship-element";
-import { useParams } from "react-router-dom";
+import { Badge } from "@/components/ui/badge";
import { DiffThread } from "@/screens/diff/node-diff/thread";
-import { DiffRow } from "@/screens/diff/node-diff/utils";
import { DiffRelationship, DiffStatus } from "@/screens/diff/node-diff/types";
-import { Badge } from "@/components/ui/badge";
+import { DiffRow } from "@/screens/diff/node-diff/utils";
import { Icon } from "@iconify-icon/react";
+import { useParams } from "react-router-dom";
+import { DiffNodeRelationshipElement } from "./node-relationship-element";
type DiffNodeRelationshipProps = {
relationship: DiffRelationship;
@@ -51,7 +51,8 @@ export const DiffNodeRelationship = ({ status, relationship }: DiffNodeRelations
)}
- }>
+ }
+ >
{relationship.elements.map((element, index: number) => (
diff --git a/frontend/app/src/screens/diff/node-diff/node.tsx b/frontend/app/src/screens/diff/node-diff/node.tsx
index 7c737e5780..a95d6c899a 100644
--- a/frontend/app/src/screens/diff/node-diff/node.tsx
+++ b/frontend/app/src/screens/diff/node-diff/node.tsx
@@ -1,18 +1,18 @@
import Accordion from "@/components/display/accordion";
-import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
-import { DiffNodeRelationship } from "./node-relationship";
-import { DiffNodeAttribute } from "./node-attribute";
-import { DiffThread } from "./thread";
-import { useLocation, useParams } from "react-router-dom";
+import { Card } from "@/components/ui/card";
+import type { DiffNode as DiffNodeType, PropertyType } from "@/screens/diff/node-diff/types";
import { DiffBadge } from "@/screens/diff/node-diff/utils";
-import { useAtomValue } from "jotai";
import { schemaKindNameState } from "@/state/atoms/schemaKindName.atom";
-import type { DiffNode as DiffNodeType, PropertyType } from "@/screens/diff/node-diff/types";
import { classNames } from "@/utils/common";
-import { useEffect, useRef } from "react";
import { Icon } from "@iconify-icon/react";
+import { useAtomValue } from "jotai";
+import { useEffect, useRef } from "react";
+import { useLocation, useParams } from "react-router-dom";
+import { DiffNodeAttribute } from "./node-attribute";
import { getNewValue, getPreviousValue } from "./node-property";
+import { DiffNodeRelationship } from "./node-relationship";
+import { DiffThread } from "./thread";
type DiffNodeProps = {
node: DiffNodeType;
@@ -38,7 +38,8 @@ export const DiffNode = ({ sourceBranch, destinationBranch, node }: DiffNodeProp
+ className={classNames(isSelectedOnNavigation && "ring-2 ring-custom-blue-500")}
+ >
{(!!node.attributes?.length || !!node.relationships?.length) && (
}
}
- className="bg-gray-100 border rounded-md">
+ className="bg-gray-100 border rounded-md"
+ >
diff --git a/frontend/app/src/screens/diff/node-diff/thread.tsx b/frontend/app/src/screens/diff/node-diff/thread.tsx
index 48b6cf0091..570d7b8d80 100644
--- a/frontend/app/src/screens/diff/node-diff/thread.tsx
+++ b/frontend/app/src/screens/diff/node-diff/thread.tsx
@@ -12,8 +12,8 @@ import { useAtom } from "jotai";
import { useContext, useState } from "react";
import { useParams } from "react-router-dom";
-import { Icon } from "@iconify-icon/react";
import { Button } from "@/components/buttons/button-primitive";
+import { Icon } from "@iconify-icon/react";
import { DiffContext } from ".";
import { DiffComments } from "./comments";
@@ -71,7 +71,8 @@ export const DiffThread = ({ path }: tDiffThread) => {
}}
className="px-2 h-6 rounded-full"
variant={"dark"}
- data-testid="data-diff-add-comment">
+ data-testid="data-diff-add-comment"
+ >
{thread?.comments?.count}
@@ -88,7 +89,8 @@ export const DiffThread = ({ path }: tDiffThread) => {
className="p-0 h-6 rounded-full"
variant={"outline"}
size={"icon"}
- data-testid="data-diff-add-comment">
+ data-testid="data-diff-add-comment"
+ >
diff --git a/frontend/app/src/screens/diff/node-diff/utils.tsx b/frontend/app/src/screens/diff/node-diff/utils.tsx
index 5e867c60c4..87616fb54c 100644
--- a/frontend/app/src/screens/diff/node-diff/utils.tsx
+++ b/frontend/app/src/screens/diff/node-diff/utils.tsx
@@ -1,3 +1,8 @@
+import Accordion from "@/components/display/accordion";
+import { DiffProperty, DiffStatus } from "@/screens/diff/node-diff/types";
+import { classNames, warnUnexpectedType } from "@/utils/common";
+import { capitalizeFirstLetter } from "@/utils/string";
+import { ReactNode } from "react";
import {
BadgeAdded,
BadgeConflict,
@@ -7,11 +12,6 @@ import {
BadgeUpdated,
DiffBadgeProps,
} from "../diff-badge";
-import { ReactNode } from "react";
-import { DiffProperty, DiffStatus } from "@/screens/diff/node-diff/types";
-import { classNames, warnUnexpectedType } from "@/utils/common";
-import Accordion from "@/components/display/accordion";
-import { capitalizeFirstLetter } from "@/utils/string";
export const diffBadges: { [key: string]: BadgeType } = {
ADDED: BadgeAdded,
@@ -88,12 +88,14 @@ export const DiffRow = ({
status === "REMOVED" && "bg-red-100 text-red-900",
status === "UPDATED" && "bg-blue-100 text-blue-900",
rightClassName
- )}>
+ )}
+ >
{right}
- }>
+ }
+ >
{children}
diff --git a/frontend/app/src/screens/edit-form-hook/dynamic-control-types.ts b/frontend/app/src/screens/edit-form-hook/dynamic-control-types.ts
index 1932a132ee..3a1220ca7a 100644
--- a/frontend/app/src/screens/edit-form-hook/dynamic-control-types.ts
+++ b/frontend/app/src/screens/edit-form-hook/dynamic-control-types.ts
@@ -1,8 +1,8 @@
import { SelectOption } from "@/components/inputs/select";
+import { SCHEMA_ATTRIBUTE_KIND } from "@/config/constants";
import { components } from "@/infraops";
import { RegisterOptions } from "react-hook-form";
import { FormFieldError } from "./form";
-import { SCHEMA_ATTRIBUTE_KIND } from "@/config/constants";
// Interface for every field in a create/edit form
export interface DynamicFieldData {
diff --git a/frontend/app/src/screens/errors/error-fallback.tsx b/frontend/app/src/screens/errors/error-fallback.tsx
index ccef134ee2..216f32afb3 100644
--- a/frontend/app/src/screens/errors/error-fallback.tsx
+++ b/frontend/app/src/screens/errors/error-fallback.tsx
@@ -88,7 +88,8 @@ function ErrorFallback({ error }: ErrorFallbackProps) {
className="underline"
href="https://discord.gg/opsmill"
target="_blank"
- rel="noreferrer">
+ rel="noreferrer"
+ >
Discord
{" or "}
@@ -96,7 +97,8 @@ function ErrorFallback({ error }: ErrorFallbackProps) {
className="underline"
href="https://github.com/opsmill/infrahub/issues/new/choose"
target="_blank"
- rel="noreferrer">
+ rel="noreferrer"
+ >
GitHub
diff --git a/frontend/app/src/screens/groups/add-group-form.tsx b/frontend/app/src/screens/groups/add-group-form.tsx
index 6c3787b4e7..2220b38403 100644
--- a/frontend/app/src/screens/groups/add-group-form.tsx
+++ b/frontend/app/src/screens/groups/add-group-form.tsx
@@ -1,11 +1,11 @@
import DynamicForm, { DynamicFormProps } from "@/components/form/dynamic-form";
-import { iNodeSchema } from "@/state/atoms/schema.atom";
-import NoDataFound from "@/screens/errors/no-data-found";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { ADD_RELATIONSHIP } from "@/graphql/mutations/relationships/addRelationship";
import { useMutation } from "@/hooks/useQuery";
-import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
+import NoDataFound from "@/screens/errors/no-data-found";
+import { iNodeSchema } from "@/state/atoms/schema.atom";
import { pluralize } from "@/utils/string";
-import { ADD_RELATIONSHIP } from "@/graphql/mutations/relationships/addRelationship";
+import { toast } from "react-toastify";
interface AddGroupFormProps extends Omit
{
objectId: string;
diff --git a/frontend/app/src/screens/groups/add-group-trigger-button.tsx b/frontend/app/src/screens/groups/add-group-trigger-button.tsx
index bef66ff2a9..dbaeb1bd60 100644
--- a/frontend/app/src/screens/groups/add-group-trigger-button.tsx
+++ b/frontend/app/src/screens/groups/add-group-trigger-button.tsx
@@ -1,12 +1,12 @@
import { ButtonWithTooltip } from "@/components/buttons/button-primitive";
-import { usePermission } from "@/hooks/usePermission";
-import { useState } from "react";
import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
-import { Icon } from "@iconify-icon/react";
-import AddGroupForm from "@/screens/groups/add-group-form";
-import { iNodeSchema } from "@/state/atoms/schema.atom";
import graphqlClient from "@/graphql/graphqlClientApollo";
import { useObjectDetails } from "@/hooks/useObjectDetails";
+import { usePermission } from "@/hooks/usePermission";
+import AddGroupForm from "@/screens/groups/add-group-form";
+import { iNodeSchema } from "@/state/atoms/schema.atom";
+import { Icon } from "@iconify-icon/react";
+import { useState } from "react";
type AddGroupTriggerButtonProps = {
schema: iNodeSchema;
@@ -34,7 +34,8 @@ export default function AddGroupTriggerButton({
tooltipContent={permission.write.message ?? "Add groups"}
tooltipEnabled
data-testid="open-group-form-button"
- {...props}>
+ {...props}
+ >
@@ -49,7 +50,8 @@ export default function AddGroupTriggerButton({
/>
}
open={isAddGroupFormOpen}
- setOpen={setIsAddGroupFormOpen}>
+ setOpen={setIsAddGroupFormOpen}
+ >
+ {...props}
+ >
{props.children ?? }
@@ -44,7 +45,8 @@ export const GroupsManagerTriggerButton = ({
title="Manage groups"
subtitle="Add and unassign groups"
/>
- }>
+ }
+ >
>
diff --git a/frontend/app/src/screens/groups/groups-manager.tsx b/frontend/app/src/screens/groups/groups-manager.tsx
index c3d02ee37a..794f838306 100644
--- a/frontend/app/src/screens/groups/groups-manager.tsx
+++ b/frontend/app/src/screens/groups/groups-manager.tsx
@@ -1,18 +1,18 @@
+import { Button } from "@/components/buttons/button-primitive";
import { SearchInput } from "@/components/ui/search-input";
-import { useState } from "react";
-import { IModelSchema } from "@/state/atoms/schema.atom";
-import useQuery from "@/hooks/useQuery";
-import { gql } from "@apollo/client";
import { getGroupsQuery } from "@/graphql/queries/groups/getGroups";
-import LoadingScreen from "@/screens/loading-screen/loading-screen";
-import NoDataFound from "@/screens/errors/no-data-found";
+import useQuery from "@/hooks/useQuery";
import ErrorScreen from "@/screens/errors/error-screen";
-import ObjectGroupsList from "@/screens/groups/object-groups-list";
+import NoDataFound from "@/screens/errors/no-data-found";
import AddGroupTriggerButton from "@/screens/groups/add-group-trigger-button";
-import { classNames } from "@/utils/common";
+import ObjectGroupsList from "@/screens/groups/object-groups-list";
import { GroupDataFromAPI } from "@/screens/groups/types";
-import { Button } from "@/components/buttons/button-primitive";
+import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import { IModelSchema } from "@/state/atoms/schema.atom";
+import { classNames } from "@/utils/common";
+import { gql } from "@apollo/client";
import { Icon } from "@iconify-icon/react";
+import { useState } from "react";
export type GroupsManagerProps = {
className?: string;
@@ -97,7 +97,8 @@ export const GroupsManager = ({ className, schema, objectId }: GroupsManagerProp
onClick={() => setDisplayAutoGenerated((v) => !v)}
className="ml-auto text-custom-blue-700 shrink-0"
variant="ghost"
- size="sm">
+ size="sm"
+ >
auto-generated
diff --git a/frontend/app/src/screens/groups/object-groups-list.tsx b/frontend/app/src/screens/groups/object-groups-list.tsx
index a7f10c5a28..edb1ba60eb 100644
--- a/frontend/app/src/screens/groups/object-groups-list.tsx
+++ b/frontend/app/src/screens/groups/object-groups-list.tsx
@@ -1,20 +1,20 @@
+import { Button } from "@/components/buttons/button-primitive";
import ItemGroup from "@/components/layouts/item-group";
+import ModalDelete from "@/components/modals/modal-delete";
import { Badge } from "@/components/ui/badge";
import { Tooltip } from "@/components/ui/tooltip";
-import { Button } from "@/components/buttons/button-primitive";
-import { Icon } from "@iconify-icon/react";
-import { Link } from "react-router-dom";
-import { getObjectDetailsUrl2 } from "@/utils/objects";
import { QSP } from "@/config/qsp";
-import ModalDelete from "@/components/modals/modal-delete";
-import { useState } from "react";
-import { useMutation } from "@/hooks/useQuery";
import graphqlClient from "@/graphql/graphqlClientApollo";
-import { pluralize } from "@/utils/string";
-import { useAtomValue } from "jotai";
-import { schemaState } from "@/state/atoms/schema.atom";
import { REMOVE_RELATIONSHIP } from "@/graphql/mutations/relationships/removeRelationship";
+import { useMutation } from "@/hooks/useQuery";
import { GroupDataFromAPI } from "@/screens/groups/types";
+import { schemaState } from "@/state/atoms/schema.atom";
+import { getObjectDetailsUrl2 } from "@/utils/objects";
+import { pluralize } from "@/utils/string";
+import { Icon } from "@iconify-icon/react";
+import { useAtomValue } from "jotai";
+import { useState } from "react";
+import { Link } from "react-router-dom";
type ObjectGroupsListProps = {
className?: string;
@@ -50,7 +50,8 @@ const ObjectGroupItem = ({ objectId, group }: ObjectGroupProps) => {
+ className="font-semibold hover:underline truncate block"
+ >
{group.display_label}
@@ -59,7 +60,8 @@ const ObjectGroupItem = ({ objectId, group }: ObjectGroupProps) => {
to={getObjectDetailsUrl2(group.__typename, group.id, [
{ name: QSP.TAB, value: "members" },
])}
- className="text-sm font-light hover:underline">
+ className="text-sm font-light hover:underline"
+ >
{pluralize(group.members.count, "member")}
@@ -93,7 +95,8 @@ const RemoveGroupButton = ({ objectId, group }: ObjectGroupProps) => {
size="icon"
className="flex-shrink-0 hover:bg-gray-200"
onClick={() => setShowDeleteModal(true)}
- data-testid="leave-group-button">
+ data-testid="leave-group-button"
+ >
diff --git a/frontend/app/src/screens/ipam/common/ip-details-card.tsx b/frontend/app/src/screens/ipam/common/ip-details-card.tsx
index 0ce31406da..32625ce3a3 100644
--- a/frontend/app/src/screens/ipam/common/ip-details-card.tsx
+++ b/frontend/app/src/screens/ipam/common/ip-details-card.tsx
@@ -48,7 +48,8 @@ export function IpDetailsCard({ schema, data, refetch }: tIpDetailsCard) {
+ )}
+ >
{relationshipData?.display_label}
),
diff --git a/frontend/app/src/screens/ipam/ip-addresses/ipam-ip-address-list.tsx b/frontend/app/src/screens/ipam/ip-addresses/ipam-ip-address-list.tsx
index 3767b6be74..0862f963d6 100644
--- a/frontend/app/src/screens/ipam/ip-addresses/ipam-ip-address-list.tsx
+++ b/frontend/app/src/screens/ipam/ip-addresses/ipam-ip-address-list.tsx
@@ -151,7 +151,8 @@ const IpamIPAddressesList = forwardRef((props, ref) => {
+ ])}
+ >
{prefixData.display_label}
@@ -202,7 +203,8 @@ const IpamIPAddressesList = forwardRef((props, ref) => {
{relatedObjectToEdit?.__typename}
@@ -210,7 +212,8 @@ const IpamIPAddressesList = forwardRef((props, ref) => {
}
open={!!relatedObjectToEdit}
- setOpen={() => setRelatedObjectToEdit(undefined)}>
+ setOpen={() => setRelatedObjectToEdit(undefined)}
+ >
{
setRelatedObjectToEdit(undefined);
diff --git a/frontend/app/src/screens/ipam/ipam-router.tsx b/frontend/app/src/screens/ipam/ipam-router.tsx
index 9e2e563dc5..6219e5f483 100644
--- a/frontend/app/src/screens/ipam/ipam-router.tsx
+++ b/frontend/app/src/screens/ipam/ipam-router.tsx
@@ -1,10 +1,10 @@
import { ButtonWithTooltip } from "@/components/buttons/button-with-tooltip";
import SlideOver from "@/components/display/slide-over";
+import ObjectForm from "@/components/form/object-form";
import { Tabs } from "@/components/tabs";
import { Card } from "@/components/ui/card";
import { DEFAULT_BRANCH_NAME } from "@/config/constants";
import { usePermission } from "@/hooks/usePermission";
-import ObjectForm from "@/components/form/object-form";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { genericsState, schemaState } from "@/state/atoms/schema.atom";
import { constructPath } from "@/utils/fetch";
@@ -124,7 +124,8 @@ function IpamRouter() {
tooltipContent={permission.write.message ?? undefined}
onClick={() => setShowCreateDrawer(true)}
className="mr-4"
- data-testid="create-object-button">
+ data-testid="create-object-button"
+ >
Add {schemaData?.label}
@@ -154,7 +155,8 @@ function IpamRouter() {
{schemaData?.kind}
@@ -162,7 +164,8 @@ function IpamRouter() {
}
open={showCreateDrawer}
- setOpen={setShowCreateDrawer}>
+ setOpen={setShowCreateDrawer}
+ >
{
diff --git a/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.state.ts b/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.state.ts
index 14ce6a4716..baf04a70e4 100644
--- a/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.state.ts
+++ b/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.state.ts
@@ -1,8 +1,8 @@
import { TreeProps } from "@/components/ui/tree";
import graphqlClient from "@/graphql/graphqlClientApollo";
import {
- GET_PREFIX_ANCESTORS,
GET_PREFIXES_ONLY,
+ GET_PREFIX_ANCESTORS,
GET_TOP_LEVEL_PREFIXES,
} from "@/graphql/queries/ipam/prefixes";
import { IP_PREFIX_GENERIC, TREE_ROOT_ID } from "@/screens/ipam/constants";
@@ -13,8 +13,8 @@ import * as R from "ramda";
import {
AncestorsData,
EMPTY_TREE,
- formatIPPrefixResponseForTreeView,
PrefixData,
+ formatIPPrefixResponseForTreeView,
updateTreeData,
} from "./utils";
diff --git a/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.tsx b/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.tsx
index 25263e10df..e5d80eb490 100644
--- a/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.tsx
+++ b/frontend/app/src/screens/ipam/ipam-tree/ipam-tree.tsx
@@ -6,23 +6,23 @@ import { useEffect, useState } from "react";
import { ITreeViewOnLoadDataProps, NodeId } from "react-accessible-treeview";
import { Link, useNavigate, useParams } from "react-router-dom";
+import { Badge } from "@/components/ui/badge";
+import { SearchInput, SearchInputProps } from "@/components/ui/search-input";
import { GET_PREFIXES_ONLY } from "@/graphql/queries/ipam/prefixes";
import { defaultIpNamespaceAtom } from "@/screens/ipam/common/namespace.state";
import { constructPathForIpam } from "@/screens/ipam/common/utils";
import { IPAM_QSP, IPAM_ROUTE, TREE_ROOT_ID } from "@/screens/ipam/constants";
import { genericsState, schemaState } from "@/state/atoms/schema.atom";
+import { debounce } from "@/utils/common";
import { StringParam, useQueryParam } from "use-query-params";
import { ipamTreeAtom, reloadIpamTreeAtom } from "./ipam-tree.state";
import {
+ EMPTY_TREE,
PrefixData,
formatIPPrefixResponseForTreeView,
getTreeItemAncestors,
updateTreeData,
- EMPTY_TREE,
} from "./utils";
-import { Badge } from "@/components/ui/badge";
-import { SearchInput, SearchInputProps } from "@/components/ui/search-input";
-import { debounce } from "@/utils/common";
export default function IpamTree({ className }: { className?: string }) {
const { prefix } = useParams();
@@ -136,7 +136,8 @@ const IpamTreeItem = ({ element }: TreeItemProps) => {
to={url}
tabIndex={-1}
className="flex items-center gap-2 w-full"
- data-testid="ipam-tree-item">
+ data-testid="ipam-tree-item"
+ >
{schema?.icon ? : }
{element.name}
{!!element.metadata?.descendantsCount && (
diff --git a/frontend/app/src/screens/ipam/ipam-tree/utils.ts b/frontend/app/src/screens/ipam/ipam-tree/utils.ts
index 85f656fa19..23e0044512 100644
--- a/frontend/app/src/screens/ipam/ipam-tree/utils.ts
+++ b/frontend/app/src/screens/ipam/ipam-tree/utils.ts
@@ -1,5 +1,5 @@
import { TreeItemProps, TreeProps } from "@/components/ui/tree";
-import { TREE_ROOT_ID, IP_PREFIX_GENERIC } from "@/screens/ipam/constants";
+import { IP_PREFIX_GENERIC, TREE_ROOT_ID } from "@/screens/ipam/constants";
export type PrefixNode = {
id: string;
diff --git a/frontend/app/src/screens/ipam/prefixes/ipam-prefix-details.tsx b/frontend/app/src/screens/ipam/prefixes/ipam-prefix-details.tsx
index 7a666aee9e..2b06035173 100644
--- a/frontend/app/src/screens/ipam/prefixes/ipam-prefix-details.tsx
+++ b/frontend/app/src/screens/ipam/prefixes/ipam-prefix-details.tsx
@@ -1,3 +1,4 @@
+import { ColorDisplay } from "@/components/display/color-display";
import SlideOver from "@/components/display/slide-over";
import ModalDelete from "@/components/modals/modal-delete";
import ProgressBarChart from "@/components/stats/progress-bar-chart";
@@ -27,7 +28,6 @@ import { forwardRef, useImperativeHandle, useState } from "react";
import { useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { StringParam, useQueryParam } from "use-query-params";
-import { ColorDisplay } from "@/components/display/color-display";
const IpamIPPrefixDetails = forwardRef((props, ref) => {
const { prefix } = useParams();
@@ -209,7 +209,8 @@ const IpamIPPrefixDetails = forwardRef((props, ref) => {
{relatedObjectToEdit?.__typename}
@@ -219,7 +220,8 @@ const IpamIPPrefixDetails = forwardRef((props, ref) => {
>
}
open={!!relatedObjectToEdit}
- setOpen={() => setRelatedObjectToEdit(undefined)}>
+ setOpen={() => setRelatedObjectToEdit(undefined)}
+ >
{
setRelatedObjectToEdit(undefined);
diff --git a/frontend/app/src/screens/ipam/prefixes/ipam-prefixes-summary-list.tsx b/frontend/app/src/screens/ipam/prefixes/ipam-prefixes-summary-list.tsx
index e1e5eafb16..b3ed636981 100644
--- a/frontend/app/src/screens/ipam/prefixes/ipam-prefixes-summary-list.tsx
+++ b/frontend/app/src/screens/ipam/prefixes/ipam-prefixes-summary-list.tsx
@@ -185,7 +185,8 @@ const IpamIPPrefixesSummaryList = forwardRef((props, ref) => {
{relatedObjectToEdit?.__typename}
@@ -195,7 +196,8 @@ const IpamIPPrefixesSummaryList = forwardRef((props, ref) => {
>
}
open={!!relatedObjectToEdit}
- setOpen={() => setRelatedObjectToEdit(undefined)}>
+ setOpen={() => setRelatedObjectToEdit(undefined)}
+ >
{
setRelatedObjectToEdit(undefined);
diff --git a/frontend/app/src/screens/layout/app-version.tsx b/frontend/app/src/screens/layout/app-version.tsx
new file mode 100644
index 0000000000..d52cf25d21
--- /dev/null
+++ b/frontend/app/src/screens/layout/app-version.tsx
@@ -0,0 +1,19 @@
+import { Skeleton } from "@/components/skeleton";
+import { CONFIG } from "@/config/config";
+import { components } from "@/infraops";
+import { fetchUrl } from "@/utils/fetch";
+import { useEffect, useState } from "react";
+
+export const AppVersion = () => {
+ const [info, setInfo] = useState(null);
+
+ useEffect(() => {
+ fetchUrl(CONFIG.INFO_URL).then((result) => setInfo(result));
+ }, []);
+
+ return (
+
+ Infrahub - v{info ? info.version : }
+
+ );
+};
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/breadcrumb-navigation.tsx b/frontend/app/src/screens/layout/breadcrumb-navigation/breadcrumb-navigation.tsx
new file mode 100644
index 0000000000..b3bfbd46b2
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/breadcrumb-navigation.tsx
@@ -0,0 +1,34 @@
+import { Breadcrumb, BreadcrumbSeparator } from "@/components/ui/breadcrumb";
+import {
+ BreadcrumbDynamicElement,
+ BreadcrumbDynamicElementProps,
+} from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-dynamic-element";
+import { breadcrumbActiveStyle } from "@/screens/layout/breadcrumb-navigation/style";
+import { classNames } from "@/utils/common";
+import React from "react";
+import { UIMatch, useMatches } from "react-router-dom";
+
+export default function BreadcrumbNavigation() {
+ const matches = useMatches() as UIMatch<
+ unknown,
+ { breadcrumb?: (match: UIMatch) => BreadcrumbDynamicElementProps }
+ >[];
+
+ const crumbs = matches
+ .map((match) => match.handle?.breadcrumb?.(match))
+ .filter((match) => !!match);
+
+ return (
+
+ {crumbs.map((crumb, index) => (
+
+
+
+
+ ))}
+
+ );
+}
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-branch-selector.tsx b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-branch-selector.tsx
new file mode 100644
index 0000000000..7ee0e76907
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-branch-selector.tsx
@@ -0,0 +1,57 @@
+import { Combobox, ComboboxContent, ComboboxList, ComboboxTrigger } from "@/components/ui/combobox";
+import { CommandEmpty, CommandItem } from "@/components/ui/command";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { breadcrumbItemStyle } from "@/screens/layout/breadcrumb-navigation/style";
+import { branchesState } from "@/state/atoms/branches.atom";
+import { classNames } from "@/utils/common";
+import { constructPath } from "@/utils/fetch";
+import { useAtomValue } from "jotai";
+import React, { useEffect, useState } from "react";
+import { Link, useNavigate } from "react-router-dom";
+
+export default function BreadcrumbBranchSelector({
+ value,
+ className,
+ ...props
+}: {
+ value: string;
+ className?: string;
+}) {
+ const branches = useAtomValue(branchesState);
+ const navigate = useNavigate();
+ const [isOpen, setIsOpen] = useState(false);
+
+ useEffect(() => {
+ if (isOpen) graphqlClient.refetchQueries({ include: ["GetBranches"] });
+ }, [isOpen]);
+
+ return (
+
+
+ {value}
+
+
+
+
+ No branch found.
+ {branches.map((branch) => {
+ const branchUrl = constructPath(`/branches/${branch.name}`);
+ return (
+ {
+ setIsOpen(false);
+ navigate(branchUrl);
+ }}
+ asChild
+ >
+ {branch.name}
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-dynamic-element.tsx b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-dynamic-element.tsx
new file mode 100644
index 0000000000..d38eefd8bd
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-dynamic-element.tsx
@@ -0,0 +1,34 @@
+import BreadcrumbBranchSelector from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-branch-selector";
+import { BreadcrumbLink } from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-link";
+import BreadcrumbObjectSelector from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-object-selector";
+import BreadcrumbSchemaSelector from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-schema-selector";
+import { BreadcrumbItem } from "@/screens/layout/breadcrumb-navigation/type";
+import { warnUnexpectedType } from "@/utils/common";
+import React from "react";
+
+export type BreadcrumbDynamicElementProps = BreadcrumbItem & {
+ isLast?: boolean;
+ className?: string;
+};
+
+export const BreadcrumbDynamicElement = ({ ...props }: BreadcrumbDynamicElementProps) => {
+ if (props.type === "link") {
+ return {props.label};
+ }
+
+ if (props.type === "select") {
+ const { value, kind, ...otherProps } = props;
+ if (kind === "schema") {
+ return ;
+ }
+
+ return ;
+ }
+
+ if (props.type === "branch") {
+ return ;
+ }
+
+ warnUnexpectedType(props);
+ return null;
+};
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-link.tsx b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-link.tsx
new file mode 100644
index 0000000000..40ba89074d
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-link.tsx
@@ -0,0 +1,16 @@
+import { breadcrumbItemStyle } from "@/screens/layout/breadcrumb-navigation/style";
+import { classNames } from "@/utils/common";
+import { Slot } from "@radix-ui/react-slot";
+import React from "react";
+import { Link, LinkProps } from "react-router-dom";
+
+export const BreadcrumbLink = React.forwardRef<
+ HTMLAnchorElement,
+ LinkProps & {
+ asChild?: boolean;
+ }
+>(({ asChild, className, ...props }, ref) => {
+ const Comp = asChild ? Slot : Link;
+
+ return ;
+});
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-loading.tsx b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-loading.tsx
new file mode 100644
index 0000000000..06f33db1d0
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-loading.tsx
@@ -0,0 +1,6 @@
+import { Spinner } from "@/components/ui/spinner";
+import React from "react";
+
+export default function BreadcrumbLoading() {
+ return ;
+}
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-object-selector.tsx b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-object-selector.tsx
new file mode 100644
index 0000000000..6ae644a982
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-object-selector.tsx
@@ -0,0 +1,56 @@
+import { useObjectDetails } from "@/hooks/useObjectDetails";
+import { useSchema } from "@/hooks/useSchema";
+import { BreadcrumbLink } from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-link";
+import BreadcrumbLoading from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-loading";
+import { IModelSchema } from "@/state/atoms/schema.atom";
+import { getObjectDetailsUrl2 } from "@/utils/objects";
+import { NetworkStatus } from "@apollo/client";
+import React from "react";
+
+export default function BreadcrumbObjectSelector({
+ kind,
+ id,
+ ...props
+}: {
+ kind: string;
+ id: string;
+ className?: string;
+}) {
+ const { schema } = useSchema(kind);
+
+ if (!schema) return ;
+
+ return ;
+}
+
+const ObjectSelector = ({
+ schema,
+ id,
+ ...props
+}: {
+ schema: IModelSchema;
+ id: string;
+ className?: string;
+}) => {
+ const { data, error, networkStatus } = useObjectDetails(schema, id);
+
+ if (networkStatus === NetworkStatus.loading) return ;
+
+ if (error) return null;
+
+ const objectList = data?.[schema.kind!].edges.map((edge: any) => edge.node);
+ if (!objectList || objectList.length === 0) return null;
+
+ const currentObject = objectList.find((node: any) => node.id === id);
+
+ if (!currentObject) return null;
+
+ return (
+
+ {currentObject.display_label}
+
+ );
+};
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-schema-selector.tsx b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-schema-selector.tsx
new file mode 100644
index 0000000000..d0daff4d21
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/items/breadcrumb-schema-selector.tsx
@@ -0,0 +1,34 @@
+import { useSchema } from "@/hooks/useSchema";
+import { BreadcrumbLink } from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-link";
+import BreadcrumbLoading from "@/screens/layout/breadcrumb-navigation/items/breadcrumb-loading";
+import { breadcrumbActiveStyle } from "@/screens/layout/breadcrumb-navigation/style";
+import { classNames } from "@/utils/common";
+import { getObjectDetailsUrl2 } from "@/utils/objects";
+import React from "react";
+
+interface BreadcrumbSchemaSelectorProps {
+ kind: string;
+ isLast?: boolean;
+ className?: string;
+}
+export default function BreadcrumbSchemaSelector({
+ isLast,
+ kind,
+ ...props
+}: BreadcrumbSchemaSelectorProps) {
+ const { schema } = useSchema(kind);
+
+ if (!schema) {
+ return ;
+ }
+
+ return (
+
+ {schema.label}
+
+ );
+}
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/style.ts b/frontend/app/src/screens/layout/breadcrumb-navigation/style.ts
new file mode 100644
index 0000000000..442f18a429
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/style.ts
@@ -0,0 +1,4 @@
+export const breadcrumbItemStyle =
+ "w-auto h-auto border-none hover:bg-gray-100 py-1 px-2 rounded-md";
+
+export const breadcrumbActiveStyle = "bg-indigo-50 text-indigo-700 hover:bg-indigo-100";
diff --git a/frontend/app/src/screens/layout/breadcrumb-navigation/type.ts b/frontend/app/src/screens/layout/breadcrumb-navigation/type.ts
new file mode 100644
index 0000000000..e76b6cac32
--- /dev/null
+++ b/frontend/app/src/screens/layout/breadcrumb-navigation/type.ts
@@ -0,0 +1,4 @@
+export type BreadcrumbItem =
+ | { type: "select"; value: string; kind: string }
+ | { type: "link"; label: string; to: string }
+ | { type: "branch"; value: string };
diff --git a/frontend/app/src/screens/layout/content.tsx b/frontend/app/src/screens/layout/content.tsx
index 808f4d3dab..39106567d0 100644
--- a/frontend/app/src/screens/layout/content.tsx
+++ b/frontend/app/src/screens/layout/content.tsx
@@ -30,7 +30,8 @@ export const ContentTitle = ({
"min-h-[4rem] bg-custom-white flex items-center px-4 border-b",
className
)}
- {...props}>
+ {...props}
+ >
{title && (
@@ -38,7 +39,7 @@ export const ContentTitle = ({
{reload && }
)}
- {description &&
{description}
}
+ {description &&
{description}
}
{children}
diff --git a/frontend/app/src/screens/layout/footer.tsx b/frontend/app/src/screens/layout/footer.tsx
deleted file mode 100644
index 830683d027..0000000000
--- a/frontend/app/src/screens/layout/footer.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import { Button } from "@/components/buttons/button-primitive";
-import { Tooltip } from "@/components/ui/tooltip";
-import {
- CONFIG,
- INFRAHUB_API_SERVER_URL,
- INFRAHUB_DOC_LOCAL,
- INFRAHUB_GITHUB_URL,
-} from "@/config/config";
-import { components } from "@/infraops";
-import { constructPath, fetchUrl } from "@/utils/fetch";
-import { Icon } from "@iconify-icon/react";
-import { useEffect, useState } from "react";
-import { Link } from "react-router-dom";
-
-const AppVersionInfo = () => {
- const [info, setInfo] = useState(null);
-
- const fetchInfo = async () => {
- const result: components["schemas"]["InfoAPI"] = await fetchUrl(CONFIG.INFO_URL);
-
- setInfo(result);
- };
-
- useEffect(() => {
- fetchInfo();
- }, []);
-
- if (!info) return null;
- return version {info.version}
;
-};
-
-export const Footer = () => {
- return (
-
- );
-};
diff --git a/frontend/app/src/screens/layout/header.tsx b/frontend/app/src/screens/layout/header.tsx
index 2b02e1f5f8..75b1771de9 100644
--- a/frontend/app/src/screens/layout/header.tsx
+++ b/frontend/app/src/screens/layout/header.tsx
@@ -1,17 +1,22 @@
-import { AccountMenu } from "@/components/account-menu";
-import { SearchAnywhere } from "@/components/search/search-anywhere";
+import BranchSelector from "@/components/branch-selector";
import { TimeFrameSelector } from "@/components/time-selector";
+import InfrahubLogo from "@/images/infrahub-logo.svg";
+import BreadcrumbNavigation from "@/screens/layout/breadcrumb-navigation/breadcrumb-navigation";
+import { constructPath } from "@/utils/fetch";
+import { Link } from "react-router-dom";
export default function Header() {
return (
-
-
+
+
+
+
-
-
-
+
-
+
+
+
);
}
diff --git a/frontend/app/src/screens/layout/layout.tsx b/frontend/app/src/screens/layout/layout.tsx
index 644def4081..d0d9badeca 100644
--- a/frontend/app/src/screens/layout/layout.tsx
+++ b/frontend/app/src/screens/layout/layout.tsx
@@ -1,18 +1,18 @@
import { QSP } from "@/config/qsp";
import { SchemaContext, withSchemaContext } from "@/decorators/withSchemaContext";
import { Branch } from "@/generated/graphql";
-import graphqlClient from "@/graphql/graphqlClientApollo";
import GET_BRANCHES from "@/graphql/queries/branches/getBranches";
+import Sidebar from "@/screens/layout/sidebar";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { branchesState, currentBranchAtom } from "@/state/atoms/branches.atom";
import { findSelectedBranch } from "@/utils/branches";
+import { NetworkStatus, useQuery } from "@apollo/client";
import { useSetAtom } from "jotai";
import { useAtomValue } from "jotai/index";
-import { useContext, useEffect, useState } from "react";
+import { useContext, useEffect } from "react";
+import { Outlet } from "react-router-dom";
import { StringParam, useQueryParam } from "use-query-params";
import Header from "./header";
-import { Sidebar } from "./sidebar";
-import { Outlet } from "react-router-dom";
function Layout() {
const branches = useAtomValue(branchesState);
@@ -20,17 +20,16 @@ function Layout() {
const { checkSchemaUpdate } = useContext(SchemaContext);
const setBranches = useSetAtom(branchesState);
const setCurrentBranch = useSetAtom(currentBranchAtom);
- const [isLoadingBranches, setIsLoadingBranches] = useState(true);
-
- const fetchBranches = async () => {
- try {
- const { data }: any = await graphqlClient.query({
- query: GET_BRANCHES,
- context: { branch: branchInQueryString },
- });
-
- return data.Branch ?? [];
- } catch (err: any) {
+ const { networkStatus } = useQuery(GET_BRANCHES, {
+ notifyOnNetworkStatusChange: true,
+ onCompleted: (data) => {
+ const branches: Branch[] = data.Branch ?? [];
+ const selectedBranch = findSelectedBranch(branches, branchInQueryString);
+
+ setBranches(branches);
+ setCurrentBranch(selectedBranch);
+ },
+ onError: (err) => {
console.error("err.message: ", err.message);
if (err?.message?.includes("Received status code 401")) {
@@ -38,34 +37,15 @@ function Layout() {
}
console.error("Error while fetching branches: ", err);
-
- return [];
- }
- };
-
- /**
- * Set branches in state atom
- */
- const setBranchesInState = async () => {
- const branches: Branch[] = await fetchBranches();
-
- const selectedBranch = findSelectedBranch(branches, branchInQueryString);
-
- setBranches(branches);
- setCurrentBranch(selectedBranch);
- setIsLoadingBranches(false);
- };
-
- useEffect(() => {
- setBranchesInState();
- }, []);
+ },
+ });
useEffect(() => {
if (branches.length === 0) return;
checkSchemaUpdate();
}, [branches.length, branchInQueryString]);
- if (isLoadingBranches) {
+ if (networkStatus === NetworkStatus.loading) {
return (
@@ -74,13 +54,15 @@ function Layout() {
}
return (
-
-
+
+
-
);
diff --git a/frontend/app/src/screens/layout/sidebar.tsx b/frontend/app/src/screens/layout/sidebar.tsx
new file mode 100644
index 0000000000..f8c6016b8f
--- /dev/null
+++ b/frontend/app/src/screens/layout/sidebar.tsx
@@ -0,0 +1,15 @@
+import { AccountMenu } from "@/components/account-menu";
+import { SearchAnywhere } from "@/components/search/search-anywhere";
+import { DesktopMenu } from "@/screens/layout/sidebar/desktop-menu";
+
+export default function Sidebar() {
+ return (
+
+ );
+}
diff --git a/frontend/app/src/screens/layout/sidebar/desktop-menu-header.tsx b/frontend/app/src/screens/layout/sidebar/desktop-menu-header.tsx
index 27199356fb..7290a4f984 100644
--- a/frontend/app/src/screens/layout/sidebar/desktop-menu-header.tsx
+++ b/frontend/app/src/screens/layout/sidebar/desktop-menu-header.tsx
@@ -1,4 +1,3 @@
-import { Circle } from "@/components/display/circle";
import { classNames } from "@/utils/common";
import { Disclosure } from "@headlessui/react";
import { Icon } from "@iconify-icon/react";
@@ -16,18 +15,18 @@ export default function DropDownMenuHeader(props: Props) {
const { title, items, icon, subItem } = props;
return (
-
+
{({ open }) => (
<>
- {icon ? (
-
+ "flex items-center p-3 text-gray-900 text-left text-sm font-medium group hover:bg-gray-100 rounded-lg"
+ )}
+ >
+ {subItem && icon ? (
+
) : (
-
+
)}
{title}
diff --git a/frontend/app/src/screens/layout/sidebar/desktop-menu-item.tsx b/frontend/app/src/screens/layout/sidebar/desktop-menu-item.tsx
index 0cd49438a9..3e12397159 100644
--- a/frontend/app/src/screens/layout/sidebar/desktop-menu-item.tsx
+++ b/frontend/app/src/screens/layout/sidebar/desktop-menu-item.tsx
@@ -20,11 +20,12 @@ export const DropDownMenuItem = ({ path, icon, title }: DropDownMenuItemProps) =
onClick={onClickMenuItem}
className={({ isActive }) =>
classNames(
- "p-2 group flex items-center rounded text-sm font-medium text-gray-600",
- isActive ? "bg-gray-300" : "hover:bg-gray-100 hover:text-gray-900"
+ "ml-4 p-2 group flex items-center rounded text-sm font-medium text-gray-600",
+ isActive ? "bg-neutral-200" : "hover:bg-gray-100 hover:text-gray-900"
)
- }>
- {icon && }
+ }
+ >
+ {icon ? : }
{title}
diff --git a/frontend/app/src/screens/layout/sidebar/desktop-menu.tsx b/frontend/app/src/screens/layout/sidebar/desktop-menu.tsx
index 43eb137b44..4011b1f5be 100644
--- a/frontend/app/src/screens/layout/sidebar/desktop-menu.tsx
+++ b/frontend/app/src/screens/layout/sidebar/desktop-menu.tsx
@@ -1,5 +1,4 @@
import { ALERT_TYPES, Alert } from "@/components/ui/alert";
-import { SearchInput } from "@/components/ui/search-input";
import { CONFIG } from "@/config/config";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
@@ -7,7 +6,7 @@ import { currentSchemaHashAtom, menuAtom } from "@/state/atoms/schema.atom";
import { classNames } from "@/utils/common";
import { fetchUrl } from "@/utils/fetch";
import { useAtom, useAtomValue } from "jotai/index";
-import { useEffect, useMemo, useState } from "react";
+import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import DropDownMenuHeader from "./desktop-menu-header";
@@ -28,7 +27,6 @@ export function DesktopMenu({ className = "" }: MenuProps) {
const [menu, setMenu] = useAtom(menuAtom);
const [isLoading, setIsLoading] = useState(false);
- const [query, setQuery] = useState("");
const fetchMenu = async () => {
if (!currentSchemaHash) return;
@@ -52,38 +50,8 @@ export function DesktopMenu({ className = "" }: MenuProps) {
fetchMenu();
}, [currentSchemaHash]);
- function filterDataByString(data: MenuItem[], searchString: string): MenuItem[] {
- const lowercaseSearch = searchString.toLowerCase();
-
- return data.reduce((acc, item) => {
- const lowercaseTitle = item.title.toLowerCase();
- const filteredChildren = filterDataByString(item.children || [], searchString);
-
- if (filteredChildren.length > 0 || lowercaseTitle.includes(lowercaseSearch)) {
- acc.push({
- ...item,
- children: filteredChildren.length > 0 ? filteredChildren : item.children,
- });
- }
-
- return acc;
- }, [] as MenuItem[]);
- }
-
- const menuFiltered = useMemo(
- () => filterDataByString(menu, query),
- [currentSchemaHash, query, menu.length]
- );
-
return (
-
setQuery(e.target.value)}
- className="shadow-none border-0 rounded-none border-b border-gray-200 focus-visible:ring-0 py-4"
- placeholder="Search menu"
- data-testid="search-menu"
- />
-
{isLoading && }
{!isLoading && (
@@ -91,8 +59,9 @@ export function DesktopMenu({ className = "" }: MenuProps) {
className="flex-grow min-h-0 overflow-y-auto overflow-x-hidden"
aria-label="Sidebar"
data-cy="sidebar-menu"
- data-testid="sidebar-menu">
- {(query !== "" ? menuFiltered : menu).map((item, index: number) => (
+ data-testid="sidebar-menu"
+ >
+ {menu.map((item, index: number) => (
-
-
-
-
- );
-}
diff --git a/frontend/app/src/screens/loading-screen/loading-screen.tsx b/frontend/app/src/screens/loading-screen/loading-screen.tsx
index 8b0fb76476..3cb49ef7c9 100644
--- a/frontend/app/src/screens/loading-screen/loading-screen.tsx
+++ b/frontend/app/src/screens/loading-screen/loading-screen.tsx
@@ -20,7 +20,8 @@ export default function LoadingScreen(props: Props) {
className={classNames(
"flex flex-col items-center justify-center h-auto w-auto",
className ?? ""
- )}>
+ )}
+ >
setShowEditModal(true)}
- data-testid="edit-button">
+ data-testid="edit-button"
+ >
Edit {schema.label}
@@ -63,7 +64,8 @@ export function DetailsButtons({ schema, objectDetailsData }: DetailsButtonsProp
data-testid="delete-button"
variant={"danger"}
size={"square"}
- onClick={() => setShowDeleteModal(true)}>
+ onClick={() => setShowDeleteModal(true)}
+ >
@@ -78,7 +80,8 @@ export function DetailsButtons({ schema, objectDetailsData }: DetailsButtonsProp
/>
}
open={showEditModal}
- setOpen={setShowEditModal}>
+ setOpen={setShowEditModal}
+ >
setShowEditModal(false)}
onUpdateComplete={() => graphqlClient.refetchQueries({ include: [schema.kind!] })}
diff --git a/frontend/app/src/screens/object-item-details/action-buttons/index.tsx b/frontend/app/src/screens/object-item-details/action-buttons/index.tsx
index d991b74175..fd8471e450 100644
--- a/frontend/app/src/screens/object-item-details/action-buttons/index.tsx
+++ b/frontend/app/src/screens/object-item-details/action-buttons/index.tsx
@@ -1,7 +1,7 @@
+import { TASK_TAB } from "@/config/constants";
+import { QSP } from "@/config/qsp";
import { StringParam, useQueryParam } from "use-query-params";
import { DetailsButtons } from "./details-buttons";
-import { QSP } from "@/config/qsp";
-import { TASK_TAB } from "@/config/constants";
import { RelationshipsButtons } from "./relationships-buttons";
export function ActionButtons(props: any) {
diff --git a/frontend/app/src/screens/object-item-details/action-buttons/relationships-buttons.tsx b/frontend/app/src/screens/object-item-details/action-buttons/relationships-buttons.tsx
index 7e5a8a064a..4ac034cfbf 100644
--- a/frontend/app/src/screens/object-item-details/action-buttons/relationships-buttons.tsx
+++ b/frontend/app/src/screens/object-item-details/action-buttons/relationships-buttons.tsx
@@ -2,7 +2,7 @@ import { ButtonWithTooltip } from "@/components/buttons/button-primitive";
import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
import DynamicForm from "@/components/form/dynamic-form";
import { SelectOption } from "@/components/inputs/select";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { QSP } from "@/config/qsp";
import graphqlClient from "@/graphql/graphqlClientApollo";
import { ADD_RELATIONSHIP } from "@/graphql/mutations/relationships/addRelationship";
@@ -93,7 +93,8 @@ export function RelationshipsButtons() {
tooltipEnabled
tooltipContent={permission.write.message ?? "Add relationship"}
onClick={() => setShowAddDrawer(true)}
- data-testid="open-relationship-form-button">
+ data-testid="open-relationship-form-button"
+ >
Add{" "}
{relationshipSchema?.label ?? relationshipSchema?.kind ?? "relationship"}
@@ -110,7 +111,8 @@ export function RelationshipsButtons() {
)
}
open={showAddDrawer}
- setOpen={setShowAddDrawer}>
+ setOpen={setShowAddDrawer}
+ >
+ data-cy="metadata-edit-button"
+ >
@@ -226,7 +227,8 @@ export default function ObjectItemDetails({
{ name: QSP.TAB, value: TASK_TAB },
{ name: QSP.TASK_ID, exclude: true },
])}
- className="flex items-center p-2 ">
+ className="flex items-center p-2 "
+ >
All tasks
@@ -251,7 +253,8 @@ export default function ObjectItemDetails({
}
open={showMetaEditModal}
- setOpen={setShowMetaEditModal}>
+ setOpen={setShowMetaEditModal}
+ >
setShowMetaEditModal(false)}
onUpdateComplete={() => graphqlClient.refetchQueries({ include: [schema.kind!] })}
diff --git a/frontend/app/src/screens/object-item-details/relationship-details-paginated.tsx b/frontend/app/src/screens/object-item-details/relationship-details-paginated.tsx
index 4454b7f42d..727fc8a415 100644
--- a/frontend/app/src/screens/object-item-details/relationship-details-paginated.tsx
+++ b/frontend/app/src/screens/object-item-details/relationship-details-paginated.tsx
@@ -9,6 +9,7 @@ import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWith
import { usePermission } from "@/hooks/usePermission";
import NoDataFound from "@/screens/errors/no-data-found";
import ObjectItemEditComponent from "@/screens/object-item-edit/object-item-edit-paginated";
+import { ObjectItemsCell, TextCell } from "@/screens/object-items/object-items-cell";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { showMetaEditState } from "@/state/atoms/metaEditFieldDetails.atom";
import { schemaState } from "@/state/atoms/schema.atom";
@@ -26,7 +27,6 @@ import { Fragment, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import { ObjectAttributeRow } from "./object-attribute-row";
-import { ObjectItemsCell, TextCell } from "@/screens/object-items/object-items-cell";
type iRelationDetailsProps = {
parentNode: any;
@@ -156,7 +156,8 @@ export default function RelationshipDetails(props: iRelationDetailsProps) {
relationshipsData.node?.id,
relationshipsData.node?.__typename
)
- )}>
+ )}
+ >
{relationshipsData.node?.display_label}
) : (
@@ -188,7 +189,8 @@ export default function RelationshipDetails(props: iRelationDetailsProps) {
});
setShowMetaEditModal(true);
}}
- data-cy="metadata-edit-button">
+ data-cy="metadata-edit-button"
+ >
@@ -229,7 +231,8 @@ export default function RelationshipDetails(props: iRelationDetailsProps) {
+ data-testid="relationship-row"
+ >
{newColumns?.map((column) => (
@@ -260,7 +263,8 @@ export default function RelationshipDetails(props: iRelationDetailsProps) {
onClick={() => {
setRelatedObjectToEdit(node);
}}
- data-cy="metadata-edit-button">
+ data-cy="metadata-edit-button"
+ >
@@ -273,7 +277,8 @@ export default function RelationshipDetails(props: iRelationDetailsProps) {
onClick={() => {
setRelatedRowToDelete(node);
}}
- data-testid="relationship-delete-button">
+ data-testid="relationship-delete-button"
+ >
|
@@ -360,7 +365,8 @@ export default function RelationshipDetails(props: iRelationDetailsProps) {
)
}
open={!!relatedObjectToEdit}
- setOpen={() => setRelatedObjectToEdit(undefined)}>
+ setOpen={() => setRelatedObjectToEdit(undefined)}
+ >
{
setRelatedObjectToEdit(undefined);
diff --git a/frontend/app/src/screens/object-item-edit/generateObjectEditFormQuery.ts b/frontend/app/src/screens/object-item-edit/generateObjectEditFormQuery.ts
index ea63b9cecc..9508e22d6e 100644
--- a/frontend/app/src/screens/object-item-edit/generateObjectEditFormQuery.ts
+++ b/frontend/app/src/screens/object-item-edit/generateObjectEditFormQuery.ts
@@ -1,7 +1,7 @@
-import { iNodeSchema, IProfileSchema } from "@/state/atoms/schema.atom";
-import { jsonToGraphQLQuery } from "json-to-graphql-query";
-import { addAttributesToRequest, addRelationshipsToRequest } from "@/graphql/utils";
import { getRelationshipsForForm } from "@/components/form/utils/getRelationshipsForForm";
+import { addAttributesToRequest, addRelationshipsToRequest } from "@/graphql/utils";
+import { IProfileSchema, iNodeSchema } from "@/state/atoms/schema.atom";
+import { jsonToGraphQLQuery } from "json-to-graphql-query";
export const generateObjectEditFormQuery = ({
schema,
diff --git a/frontend/app/src/screens/object-item-edit/object-item-edit-paginated.tsx b/frontend/app/src/screens/object-item-edit/object-item-edit-paginated.tsx
index a4a4310f4c..4e7667d68a 100644
--- a/frontend/app/src/screens/object-item-edit/object-item-edit-paginated.tsx
+++ b/frontend/app/src/screens/object-item-edit/object-item-edit-paginated.tsx
@@ -1,22 +1,22 @@
+import ObjectForm, { ObjectFormProps } from "@/components/form/object-form";
+import { getUpdateMutationFromFormData } from "@/components/form/utils/mutations/getUpdateMutationFromFormData";
import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import graphqlClient from "@/graphql/graphqlClientApollo";
import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
import useQuery from "@/hooks/useQuery";
+import { useSchema } from "@/hooks/useSchema";
import { DynamicFieldData } from "@/screens/edit-form-hook/dynamic-control-types";
import ErrorScreen from "@/screens/errors/error-screen";
import NoDataFound from "@/screens/errors/no-data-found";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import { generateObjectEditFormQuery } from "@/screens/object-item-edit/generateObjectEditFormQuery";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { datetimeAtom } from "@/state/atoms/time.atom";
+import { areObjectArraysEqualById } from "@/utils/array";
import { stringifyWithoutQuotes } from "@/utils/string";
import { gql } from "@apollo/client";
import { useAtomValue } from "jotai/index";
import { toast } from "react-toastify";
-import ObjectForm, { ObjectFormProps } from "@/components/form/object-form";
-import { getUpdateMutationFromFormData } from "@/components/form/utils/mutations/getUpdateMutationFromFormData";
-import { areObjectArraysEqualById } from "@/utils/array";
-import { generateObjectEditFormQuery } from "@/screens/object-item-edit/generateObjectEditFormQuery";
-import { useSchema } from "@/hooks/useSchema";
interface Props {
objectname: string;
diff --git a/frontend/app/src/screens/object-item-meta-edit/object-item-meta-edit.tsx b/frontend/app/src/screens/object-item-meta-edit/object-item-meta-edit.tsx
index 95c783c41e..304a27b0d4 100644
--- a/frontend/app/src/screens/object-item-meta-edit/object-item-meta-edit.tsx
+++ b/frontend/app/src/screens/object-item-meta-edit/object-item-meta-edit.tsx
@@ -1,3 +1,5 @@
+import DynamicForm from "@/components/form/dynamic-form";
+import { getRelationshipDefaultValue } from "@/components/form/utils/getRelationshipDefaultValue";
import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import graphqlClient from "@/graphql/graphqlClientApollo";
import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
@@ -9,9 +11,7 @@ import { stringifyWithoutQuotes } from "@/utils/string";
import { gql } from "@apollo/client";
import { useAtomValue } from "jotai/index";
import { toast } from "react-toastify";
-import DynamicForm from "@/components/form/dynamic-form";
import { mapValues } from "remeda";
-import { getRelationshipDefaultValue } from "@/components/form/utils/getRelationshipDefaultValue";
interface Props {
row: any;
diff --git a/frontend/app/src/screens/object-items/object-items-cell.tsx b/frontend/app/src/screens/object-items/object-items-cell.tsx
index b2342a8219..b208048905 100644
--- a/frontend/app/src/screens/object-items/object-items-cell.tsx
+++ b/frontend/app/src/screens/object-items/object-items-cell.tsx
@@ -1,14 +1,14 @@
-import { getObjectDetailsUrl2 } from "@/utils/objects";
-import { Link, LinkProps } from "react-router-dom";
+import { Badge } from "@/components/ui/badge";
+import { AttributeSchema, RelationshipSchema } from "@/screens/schema/types";
+import { classNames } from "@/utils/common";
import {
- getDisplayValue,
RelationshipManyType,
RelationshipOneType,
+ getDisplayValue,
} from "@/utils/getObjectItemDisplayValue";
-import { AttributeSchema, RelationshipSchema } from "@/screens/schema/types";
-import { Badge } from "@/components/ui/badge";
-import { classNames } from "@/utils/common";
+import { getObjectDetailsUrl2 } from "@/utils/objects";
import { HTMLAttributes } from "react";
+import { Link, LinkProps } from "react-router-dom";
type ObjectItemsCellProps = {
row: any;
@@ -51,7 +51,8 @@ export const RelationshipOneCell = ({ data }: { data: RelationshipOneType }) =>
return (
+ className="hover:underline"
+ >
{data.node.display_label}
);
diff --git a/frontend/app/src/screens/object-items/object-items-paginated.tsx b/frontend/app/src/screens/object-items/object-items-paginated.tsx
index 418cc74671..21c136540b 100644
--- a/frontend/app/src/screens/object-items/object-items-paginated.tsx
+++ b/frontend/app/src/screens/object-items/object-items-paginated.tsx
@@ -1,5 +1,7 @@
import { ButtonWithTooltip } from "@/components/buttons/button-primitive";
import { Filters } from "@/components/filters/filters";
+import { ObjectCreateFormTrigger } from "@/components/form/object-create-form-trigger";
+import ModalDeleteObject from "@/components/modals/modal-delete-object";
import { Pagination } from "@/components/ui/pagination";
import { SearchInput, SearchInputProps } from "@/components/ui/search-input";
import {
@@ -9,22 +11,20 @@ import {
SEARCH_PARTIAL_MATCH,
} from "@/config/constants";
import useFilters, { Filter } from "@/hooks/useFilters";
+import { useObjectItems } from "@/hooks/useObjectItems";
import { usePermission } from "@/hooks/usePermission";
import { useTitle } from "@/hooks/useTitle";
import ErrorScreen from "@/screens/errors/error-screen";
import NoDataFound from "@/screens/errors/no-data-found";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
+import { ObjectItemsCell, TextCell } from "@/screens/object-items/object-items-cell";
import { IModelSchema } from "@/state/atoms/schema.atom";
import { classNames, debounce } from "@/utils/common";
+import { getDisplayValue } from "@/utils/getObjectItemDisplayValue";
import { getSchemaObjectColumns } from "@/utils/getSchemaObjectColumns";
import { Icon } from "@iconify-icon/react";
import { useState } from "react";
import { Navigate } from "react-router-dom";
-import { useObjectItems } from "@/hooks/useObjectItems";
-import { ObjectItemsCell, TextCell } from "@/screens/object-items/object-items-cell";
-import { getDisplayValue } from "@/utils/getObjectItemDisplayValue";
-import { ObjectCreateFormTrigger } from "@/components/form/object-create-form-trigger";
-import ModalDeleteObject from "@/components/modals/modal-delete-object";
type ObjectItemsProps = {
schema: IModelSchema;
@@ -51,12 +51,16 @@ export default function ObjectItems({
return ;
}
+ if (!schema.kind) {
+ return ;
+ }
+
// Get all the needed columns (attributes + relationships)
const columns = getSchemaObjectColumns({ schema: schema, forListView: true });
const { loading, error, data = {}, refetch } = useObjectItems(schema, filters);
- const result = data && schema?.kind ? data[kindFilter?.value || schema?.kind] ?? {} : {};
+ const result = data && schema?.kind ? (data[kindFilter?.value || schema?.kind] ?? {}) : {};
const { count = "...", edges } = result;
@@ -99,7 +103,8 @@ export default function ObjectItems({
<>
+ data-testid="object-items"
+ >
+ data-cy="object-table-row"
+ >
{columns?.map((attribute, index) => {
return (
@@ -163,7 +169,8 @@ export default function ObjectItems({
onClick={() => {
setRowToDelete(row);
setDeleteModal(true);
- }}>
+ }}
+ >
|
diff --git a/frontend/app/src/screens/objects/hierarchical-tree.tsx b/frontend/app/src/screens/objects/hierarchical-tree.tsx
index 7b14bfb732..1f105cf416 100644
--- a/frontend/app/src/screens/objects/hierarchical-tree.tsx
+++ b/frontend/app/src/screens/objects/hierarchical-tree.tsx
@@ -1,23 +1,23 @@
-import { useAtomValue } from "jotai";
import { Tree, TreeItemProps, TreeProps } from "@/components/ui/tree";
-import { EMPTY_TREE, PrefixNode, updateTreeData } from "@/screens/ipam/ipam-tree/utils";
-import { genericsState, IModelSchema, schemaState } from "@/state/atoms/schema.atom";
-import { useEffect, useState } from "react";
-import { useLazyQuery } from "@/hooks/useQuery";
-import { gql } from "@apollo/client";
-import { TREE_ROOT_ID } from "@/screens/ipam/constants";
-import { Link, useNavigate } from "react-router-dom";
-import { Icon } from "@iconify-icon/react";
-import { constructPath } from "@/utils/fetch";
-import { ITreeViewOnLoadDataProps, NodeId } from "react-accessible-treeview";
-import { getObjectDetailsUrl } from "@/utils/objects";
import {
objectAncestorsQuery,
objectChildrenQuery,
objectTopLevelTreeQuery,
} from "@/graphql/queries/objects/objectTreeQuery";
+import { useLazyQuery } from "@/hooks/useQuery";
+import { TREE_ROOT_ID } from "@/screens/ipam/constants";
+import { EMPTY_TREE, PrefixNode, updateTreeData } from "@/screens/ipam/ipam-tree/utils";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
+import { IModelSchema, genericsState, schemaState } from "@/state/atoms/schema.atom";
import { datetimeAtom } from "@/state/atoms/time.atom";
+import { constructPath } from "@/utils/fetch";
+import { getObjectDetailsUrl } from "@/utils/objects";
+import { gql } from "@apollo/client";
+import { Icon } from "@iconify-icon/react";
+import { useAtomValue } from "jotai";
+import { useEffect, useState } from "react";
+import { ITreeViewOnLoadDataProps, NodeId } from "react-accessible-treeview";
+import { Link, useNavigate } from "react-router-dom";
export type HierarchicalTreeProps = {
schema: IModelSchema;
@@ -156,7 +156,8 @@ const ObjectTreeItem = ({ element }: TreeItemProps) => {
to={url}
tabIndex={-1}
className="flex items-center gap-2"
- data-testid="hierarchical-tree-item">
+ data-testid="hierarchical-tree-item"
+ >
{schema?.icon ? : }
{element.name}
diff --git a/frontend/app/src/screens/objects/object-header.tsx b/frontend/app/src/screens/objects/object-header.tsx
index 649d3ed22e..ba6827dd4c 100644
--- a/frontend/app/src/screens/objects/object-header.tsx
+++ b/frontend/app/src/screens/objects/object-header.tsx
@@ -1,16 +1,16 @@
+import { ObjectHelpButton } from "@/components/menu/object-help-button";
+import { Skeleton } from "@/components/skeleton";
+import { Badge } from "@/components/ui/badge";
+import { PROFILE_KIND } from "@/config/constants";
import graphqlClient from "@/graphql/graphqlClientApollo";
+import useFilters from "@/hooks/useFilters";
+import { useObjectDetails } from "@/hooks/useObjectDetails";
+import { useObjectItems } from "@/hooks/useObjectItems";
import Content from "@/screens/layout/content";
import { IModelSchema } from "@/state/atoms/schema.atom";
-import { Badge } from "@/components/ui/badge";
import { constructPath } from "@/utils/fetch";
-import { PROFILE_KIND } from "@/config/constants";
-import { Link } from "react-router-dom";
-import { useObjectItems } from "@/hooks/useObjectItems";
-import { ObjectHelpButton } from "@/components/menu/object-help-button";
-import useFilters from "@/hooks/useFilters";
import { Icon } from "@iconify-icon/react";
-import { useObjectDetails } from "@/hooks/useObjectDetails";
-import { Skeleton } from "@/components/skeleton";
+import { Link } from "react-router-dom";
type ObjectHeaderProps = {
schema: IModelSchema;
@@ -40,7 +40,8 @@ const ObjectItemsHeader = ({ schema }: ObjectHeaderProps) => {
+ className="flex items-center cursor-pointer"
+ >
{breadcrumbModelLabel}
@@ -51,7 +52,8 @@ const ObjectItemsHeader = ({ schema }: ObjectHeaderProps) => {
description={schema.description}
isReloadLoading={loading}
reload={() => graphqlClient.refetchQueries({ include: [schema.kind!] })}
- data-testid="object-header">
+ data-testid="object-header"
+ >
+ className="flex items-center cursor-pointer"
+ >
{breadcrumbModelLabel}
@@ -98,7 +101,8 @@ const ObjectDetailsHeader = ({ schema, objectId }: ObjectHeaderProps & { objectI
description={schema.description}
isReloadLoading={loading}
reload={() => graphqlClient.refetchQueries({ include: [schema.kind!] })}
- data-testid="object-header">
+ data-testid="object-header"
+ >
+ {...props}
+ >
Approve
);
diff --git a/frontend/app/src/screens/proposed-changes/action-button/pc-close-button.tsx b/frontend/app/src/screens/proposed-changes/action-button/pc-close-button.tsx
index 3c983c19af..3ae627d1e4 100644
--- a/frontend/app/src/screens/proposed-changes/action-button/pc-close-button.tsx
+++ b/frontend/app/src/screens/proposed-changes/action-button/pc-close-button.tsx
@@ -1,16 +1,16 @@
import { Button, ButtonProps } from "@/components/buttons/button-primitive";
-import React, { useState } from "react";
-import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { PROPOSED_CHANGES_OBJECT } from "@/config/constants";
-import { stringifyWithoutQuotes } from "@/utils/string";
-import { gql } from "@apollo/client";
import graphqlClient from "@/graphql/graphqlClientApollo";
-import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
-import { useAtomValue } from "jotai/index";
+import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { usePermission } from "@/hooks/usePermission";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { datetimeAtom } from "@/state/atoms/time.atom";
-import { usePermission } from "@/hooks/usePermission";
+import { stringifyWithoutQuotes } from "@/utils/string";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai/index";
+import React, { useState } from "react";
+import { toast } from "react-toastify";
interface PcCloseButtonProps extends ButtonProps {
proposedChangeId: string;
@@ -78,7 +78,8 @@ export const PcCloseButton = ({ proposedChangeId, state, ...props }: PcCloseButt
onClick={handleClose}
isLoading={isLoadingClose}
disabled={!permission.write.allow || state === "merged"}
- {...props}>
+ {...props}
+ >
{state === "closed" ? "Re-open" : "Close"}
);
diff --git a/frontend/app/src/screens/proposed-changes/action-button/pc-merge-button.tsx b/frontend/app/src/screens/proposed-changes/action-button/pc-merge-button.tsx
index 289ebe34e1..c84a5d5d1e 100644
--- a/frontend/app/src/screens/proposed-changes/action-button/pc-merge-button.tsx
+++ b/frontend/app/src/screens/proposed-changes/action-button/pc-merge-button.tsx
@@ -1,16 +1,16 @@
import { Button, ButtonProps } from "@/components/buttons/button-primitive";
-import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { PROPOSED_CHANGES_OBJECT } from "@/config/constants";
-import { stringifyWithoutQuotes } from "@/utils/string";
-import { gql } from "@apollo/client";
import graphqlClient from "@/graphql/graphqlClientApollo";
-import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
-import React, { useState } from "react";
-import { useAtomValue } from "jotai/index";
+import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { usePermission } from "@/hooks/usePermission";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { datetimeAtom } from "@/state/atoms/time.atom";
-import { usePermission } from "@/hooks/usePermission";
+import { stringifyWithoutQuotes } from "@/utils/string";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai/index";
+import React, { useState } from "react";
+import { toast } from "react-toastify";
interface PcMergeButtonProps extends ButtonProps {
proposedChangeId: string;
@@ -78,7 +78,8 @@ export const PcMergeButton = ({
onClick={handleMerge}
isLoading={isLoadingMerge}
disabled={!permission.write.allow || state === "closed" || state === "merged"}
- {...props}>
+ {...props}
+ >
Merge
);
diff --git a/frontend/app/src/screens/proposed-changes/conversations.tsx b/frontend/app/src/screens/proposed-changes/conversations.tsx
index a709e3125b..6af0a7f477 100644
--- a/frontend/app/src/screens/proposed-changes/conversations.tsx
+++ b/frontend/app/src/screens/proposed-changes/conversations.tsx
@@ -1,7 +1,9 @@
import { AddComment } from "@/components/conversations/add-comment";
import { Thread } from "@/components/conversations/thread";
+import { Card } from "@/components/ui/card";
+import { FormRef } from "@/components/ui/form";
import {
- ACCOUNT_OBJECT,
+ ACCOUNT_GENERIC_OBJECT,
PROPOSED_CHANGES_CHANGE_THREAD_OBJECT,
PROPOSED_CHANGES_THREAD_COMMENT_OBJECT,
PROPOSED_CHANGES_THREAD_OBJECT,
@@ -16,15 +18,13 @@ import ErrorScreen from "@/screens/errors/error-screen";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
import { datetimeAtom } from "@/state/atoms/time.atom";
+import { classNames } from "@/utils/common";
import { stringifyWithoutQuotes } from "@/utils/string";
-import { gql, NetworkStatus } from "@apollo/client";
+import { NetworkStatus, gql } from "@apollo/client";
import { formatISO } from "date-fns";
import { useAtomValue } from "jotai/index";
import { HTMLAttributes, useRef } from "react";
import { useParams } from "react-router-dom";
-import { FormRef } from "@/components/ui/form";
-import { Card } from "@/components/ui/card";
-import { classNames } from "@/utils/common";
export const Conversations = ({ className, ...props }: HTMLAttributes) => {
const { proposedChangeId } = useParams();
@@ -36,7 +36,7 @@ export const Conversations = ({ className, ...props }: HTMLAttributes {
const { user } = useAuth();
@@ -37,6 +38,8 @@ export const ProposedChangeCreateForm = () => {
const [createProposedChange, { error }] = useMutation(CREATE_PROPOSED_CHANGE);
+ if (branches.length === 0) return ;
+
return (
+
}
reload={() => refetch()}
- isReloadLoading={loading}>
+ isReloadLoading={loading}
+ >
{
tooltipEnabled={!permission.write.allow}
tooltipContent={permission.write.message ?? undefined}
onClick={() => navigate(constructPath("/proposed-changes/new"))}
- data-testid="add-proposed-changes-button">
+ data-testid="add-proposed-changes-button"
+ >
New proposed change
diff --git a/frontend/app/src/screens/proposed-changes/proposed-change-details.tsx b/frontend/app/src/screens/proposed-changes/proposed-change-details.tsx
index f7a1b1b7f5..f94ad3d7e5 100644
--- a/frontend/app/src/screens/proposed-changes/proposed-change-details.tsx
+++ b/frontend/app/src/screens/proposed-changes/proposed-change-details.tsx
@@ -1,23 +1,23 @@
import { Avatar } from "@/components/display/avatar";
import { DateDisplay } from "@/components/display/date-display";
+import { MarkdownViewer } from "@/components/editor/markdown-viewer";
+import { Property, PropertyList } from "@/components/table/property-list";
+import { Badge } from "@/components/ui/badge";
+import { CardWithBorder } from "@/components/ui/card";
import { Tooltip } from "@/components/ui/tooltip";
+import { PcApproveButton } from "@/screens/proposed-changes/action-button/pc-approve-button";
+import { PcCloseButton } from "@/screens/proposed-changes/action-button/pc-close-button";
+import { PcMergeButton } from "@/screens/proposed-changes/action-button/pc-merge-button";
+import { Conversations } from "@/screens/proposed-changes/conversations";
+import { ProposedChangeEditTrigger } from "@/screens/proposed-changes/proposed-change-edit-trigger";
import { proposedChangedState } from "@/state/atoms/proposedChanges.atom";
+import { classNames } from "@/utils/common";
import { constructPath } from "@/utils/fetch";
import { getProposedChangesStateBadgeType } from "@/utils/proposed-changes";
import { Icon } from "@iconify-icon/react";
import { useAtom } from "jotai";
import React, { HTMLAttributes } from "react";
import { useNavigate, useParams } from "react-router-dom";
-import { CardWithBorder } from "@/components/ui/card";
-import { Property, PropertyList } from "@/components/table/property-list";
-import { Badge } from "@/components/ui/badge";
-import { ProposedChangeEditTrigger } from "@/screens/proposed-changes/proposed-change-edit-trigger";
-import { PcCloseButton } from "@/screens/proposed-changes/action-button/pc-close-button";
-import { PcMergeButton } from "@/screens/proposed-changes/action-button/pc-merge-button";
-import { PcApproveButton } from "@/screens/proposed-changes/action-button/pc-approve-button";
-import { Conversations } from "@/screens/proposed-changes/conversations";
-import { classNames } from "@/utils/common";
-import { MarkdownViewer } from "@/components/editor/markdown-viewer";
export const ProposedChangeDetails = ({ className, ...props }: HTMLAttributes) => {
const { proposedChangeId } = useParams();
@@ -133,7 +133,8 @@ export const ProposedChangeDetails = ({ className, ...props }: HTMLAttributes
navigate(path)}
- className="text-base font-semibold leading-6 text-gray-900 cursor-pointer hover:underline">
+ className="text-base font-semibold leading-6 text-gray-900 cursor-pointer hover:underline"
+ >
Proposed change
diff --git a/frontend/app/src/screens/proposed-changes/proposed-change-edit-trigger.tsx b/frontend/app/src/screens/proposed-changes/proposed-change-edit-trigger.tsx
index 8b0164cd04..4236dfa47b 100644
--- a/frontend/app/src/screens/proposed-changes/proposed-change-edit-trigger.tsx
+++ b/frontend/app/src/screens/proposed-changes/proposed-change-edit-trigger.tsx
@@ -1,13 +1,13 @@
-import { usePermission } from "@/hooks/usePermission";
-import { useSchema } from "@/hooks/useSchema";
-import { PROPOSED_CHANGES_EDITABLE_STATE, PROPOSED_CHANGES_OBJECT } from "@/config/constants";
-import React, { useState } from "react";
import { ButtonWithTooltip } from "@/components/buttons/button-primitive";
-import { Icon } from "@iconify-icon/react";
import SlideOver from "@/components/display/slide-over";
import { ObjectHelpButton } from "@/components/menu/object-help-button";
-import { ProposedChangeEditForm } from "@/screens/proposed-changes/form/proposed-change-edit-form";
+import { PROPOSED_CHANGES_EDITABLE_STATE, PROPOSED_CHANGES_OBJECT } from "@/config/constants";
import graphqlClient from "@/graphql/graphqlClientApollo";
+import { usePermission } from "@/hooks/usePermission";
+import { useSchema } from "@/hooks/useSchema";
+import { ProposedChangeEditForm } from "@/screens/proposed-changes/form/proposed-change-edit-form";
+import { Icon } from "@iconify-icon/react";
+import React, { useState } from "react";
export const ProposedChangeEditTrigger = ({
proposedChangesDetails,
@@ -30,7 +30,8 @@ export const ProposedChangeEditTrigger = ({
tooltipEnabled={!permission.write.allow}
tooltipContent={permission.write.message ?? undefined}
onClick={() => setShowEditDrawer(true)}
- data-testid="edit-button">
+ data-testid="edit-button"
+ >
@@ -57,7 +58,8 @@ export const ProposedChangeEditTrigger = ({
}
open={showEditDrawer}
- setOpen={setShowEditDrawer}>
+ setOpen={setShowEditDrawer}
+ >
{
diff --git a/frontend/app/src/screens/repository/repository-action-menu.tsx b/frontend/app/src/screens/repository/repository-action-menu.tsx
index 0ca963f199..85ed47e024 100644
--- a/frontend/app/src/screens/repository/repository-action-menu.tsx
+++ b/frontend/app/src/screens/repository/repository-action-menu.tsx
@@ -1,21 +1,21 @@
import { Icon } from "@iconify-icon/react";
import { Button, ButtonWithTooltip } from "@/components/buttons/button-primitive";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
-import { useMutation } from "@/hooks/useQuery";
import {
CHECK_REPOSITORY_CONNECTIVITY,
REIMPORT_LAST_COMMIT,
} from "@/graphql/mutations/repository/actions";
-import { toast } from "react-toastify";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
-import { useState } from "react";
+import { useMutation } from "@/hooks/useQuery";
import { Dialog } from "@headlessui/react";
+import { useState } from "react";
+import { toast } from "react-toastify";
const RepositoryActionMenu = ({ repositoryId }: { repositoryId: string }) => {
const [isOpen, setIsOpen] = useState(false);
@@ -29,14 +29,15 @@ const RepositoryActionMenu = ({ repositoryId }: { repositoryId: string }) => {
tooltipEnabled
variant="ghost"
size="square"
- className="p-4">
+ className="p-4"
+ >
setIsOpen(true)}>
-
+
Check connectivity
@@ -152,7 +153,7 @@ const ReimportLastCommitAction = ({ repositoryId }: { repositoryId: string }) =>
return (
reimportLastCommit()}>
-
+
Reimport last commit
);
diff --git a/frontend/app/src/screens/repository/repository-form.tsx b/frontend/app/src/screens/repository/repository-form.tsx
index 4406d7c6ec..909870e2df 100644
--- a/frontend/app/src/screens/repository/repository-form.tsx
+++ b/frontend/app/src/screens/repository/repository-form.tsx
@@ -1,20 +1,20 @@
-import { Form, FormSubmit } from "@/components/ui/form";
+import { Button } from "@/components/buttons/button-primitive";
+import { DynamicInput } from "@/components/form/dynamic-form";
+import RelationshipField from "@/components/form/fields/relationship.field";
+import { NodeFormProps } from "@/components/form/node-form";
+import { getFormFieldsFromSchema } from "@/components/form/utils/getFormFieldsFromSchema";
+import { getCreateMutationFromFormData } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
import { Card, CardProps } from "@/components/ui/card";
+import { Form, FormSubmit } from "@/components/ui/form";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { createObject } from "@/graphql/mutations/objects/createObject";
+import { useAuth } from "@/hooks/useAuth";
+import { currentBranchAtom } from "@/state/atoms/branches.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
import { classNames } from "@/utils/common";
import { stringifyWithoutQuotes } from "@/utils/string";
import { gql } from "@apollo/client";
-import graphqlClient from "@/graphql/graphqlClientApollo";
import { useAtomValue } from "jotai/index";
-import { currentBranchAtom } from "@/state/atoms/branches.atom";
-import { datetimeAtom } from "@/state/atoms/time.atom";
-import { getCreateMutationFromFormData } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
-import { getFormFieldsFromSchema } from "@/components/form/utils/getFormFieldsFromSchema";
-import { useAuth } from "@/hooks/useAuth";
-import { DynamicInput } from "@/components/form/dynamic-form";
-import { NodeFormProps } from "@/components/form/node-form";
-import { createObject } from "@/graphql/mutations/objects/createObject";
-import RelationshipField from "@/components/form/fields/relationship.field";
-import { Button } from "@/components/buttons/button-primitive";
import React from "react";
const RepositoryForm = ({
@@ -65,7 +65,8 @@ const RepositoryForm = ({
await graphqlClient.reFetchObservableQueries();
if (onSuccess) await onSuccess(result?.data?.[`${schema?.kind}Create`]);
- }}>
+ }}
+ >
{gitUrlFieldProps && (
}
- enabled>
+ enabled
+ >
{roundNumber(utilizationOverall, 0)}%
diff --git a/frontend/app/src/screens/resource-manager/constants.ts b/frontend/app/src/screens/resource-manager/constants.ts
index 7151afdc14..6edb4bc960 100644
--- a/frontend/app/src/screens/resource-manager/constants.ts
+++ b/frontend/app/src/screens/resource-manager/constants.ts
@@ -2,3 +2,6 @@ export const RESOURCE_GENERIC_KIND = "CoreResourcePool";
export const RESOURCE_POOL_UTILIZATION_KIND = "InfrahubResourcePoolUtilization";
export const RESOURCE_POOL_ALLOCATED_KIND = "InfrahubResourcePoolAllocated";
export const NUMBER_POOL_KIND = "CoreNumberPool";
+
+export const NUMBER_POOL_NODE_FIELD = "node";
+export const NUMBER_POOL_NODE_ATTRIBUTE_FIELD = "node_attribute";
diff --git a/frontend/app/src/screens/resource-manager/number-pool-form.tsx b/frontend/app/src/screens/resource-manager/number-pool-form.tsx
index 53011a0109..8bbd2fa0f9 100644
--- a/frontend/app/src/screens/resource-manager/number-pool-form.tsx
+++ b/frontend/app/src/screens/resource-manager/number-pool-form.tsx
@@ -1,27 +1,41 @@
import { Button } from "@/components/buttons/button-primitive";
-import DropdownField from "@/components/form/fields/dropdown.field";
+import { DEFAULT_FORM_FIELD_VALUE } from "@/components/form/constants";
+import { LabelFormField } from "@/components/form/fields/common";
import InputField from "@/components/form/fields/input.field";
import NumberField from "@/components/form/fields/number.field";
import { NodeFormProps } from "@/components/form/node-form";
-import { FormFieldValue } from "@/components/form/type";
+import { FormAttributeValue, FormFieldValue } from "@/components/form/type";
import { getCurrentFieldValue } from "@/components/form/utils/getFieldDefaultValue";
import { getCreateMutationFromFormDataOnly } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
-import { SelectOption } from "@/components/inputs/select";
-import { Alert, ALERT_TYPES } from "@/components/ui/alert";
-import { Form, FormSubmit } from "@/components/ui/form";
-import { NUMBER_POOL_OBJECT } from "@/config/constants";
+import { updateFormFieldValue } from "@/components/form/utils/updateFormFieldValue";
+import { isRequired } from "@/components/form/utils/validation";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { Badge } from "@/components/ui/badge";
+import {
+ Combobox,
+ ComboboxContent,
+ ComboboxItem,
+ ComboboxList,
+ ComboboxTrigger,
+} from "@/components/ui/combobox";
+import { Form, FormField, FormInput, FormMessage, FormSubmit } from "@/components/ui/form";
+import { NUMBER_POOL_OBJECT, SCHEMA_ATTRIBUTE_KIND } from "@/config/constants";
import graphqlClient from "@/graphql/graphqlClientApollo";
import { createObject } from "@/graphql/mutations/objects/createObject";
import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
-import { useFormValues } from "@/hooks/useFormValues";
+import {
+ NUMBER_POOL_NODE_ATTRIBUTE_FIELD,
+ NUMBER_POOL_NODE_FIELD,
+} from "@/screens/resource-manager/constants";
+import { AttributeSchema } from "@/screens/schema/types";
import { currentBranchAtom } from "@/state/atoms/branches.atom";
-import { schemaState } from "@/state/atoms/schema.atom";
+import { iNodeSchema, schemaState } from "@/state/atoms/schema.atom";
import { datetimeAtom } from "@/state/atoms/time.atom";
import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
import { stringifyWithoutQuotes } from "@/utils/string";
import { gql } from "@apollo/client";
import { useAtomValue } from "jotai";
-import { useEffect } from "react";
+import { useEffect, useState } from "react";
import { FieldValues, useForm, useFormContext } from "react-hook-form";
import { toast } from "react-toastify";
@@ -132,50 +146,145 @@ export const NumberPoolForm = ({
};
const NodeAttributesSelects = () => {
- const schemaList = useAtomValue(schemaState);
+ const nodes = useAtomValue(schemaState);
- const { resetField } = useFormContext();
+ const form = useFormContext();
+ const selectedNodeField: FormAttributeValue = form.watch(NUMBER_POOL_NODE_FIELD);
+ const selectedNode = nodes.find((node) => node.kind === selectedNodeField?.value);
- // Watch form value to rebuild 2nd select options
- const { node } = useFormValues();
-
- const availableSchemaList = schemaList?.filter(
- (schema) =>
- !!schema.attributes?.find((attribute) => attribute.kind === "Number" && !attribute.read_only)
+ const nodesWithNumberAttributes: Array = nodes.filter((node) =>
+ node.attributes?.some(
+ (attribute) => attribute.kind === SCHEMA_ATTRIBUTE_KIND.NUMBER && !attribute.read_only
+ )
);
- const selectedNode = availableSchemaList.find((schema) => schema.kind === node?.value);
- const nodesOptions: SelectOption[] = availableSchemaList.map((schema) => ({
- id: schema.kind as string,
- name: schema.label as string,
- badge: schema.namespace,
- }));
-
- const attributesOptions: SelectOption[] = selectedNode?.attributes
- ? selectedNode.attributes
- ?.filter((attribute) => attribute.kind === "Number")
- ?.map((attribute) => ({ id: attribute.name as string, name: attribute.label as string }))
- : [];
+ const numberAttributeOptions: Array =
+ selectedNode?.attributes?.filter(
+ (attribute) => attribute.kind === SCHEMA_ATTRIBUTE_KIND.NUMBER
+ ) ?? [];
useEffect(() => {
- resetField("node_attribute");
- }, [node?.value]);
+ if (numberAttributeOptions.length === 1) {
+ form.setValue(
+ NUMBER_POOL_NODE_ATTRIBUTE_FIELD,
+ updateFormFieldValue(numberAttributeOptions[0].name, DEFAULT_FORM_FIELD_VALUE)
+ );
+ } else {
+ form.resetField(NUMBER_POOL_NODE_ATTRIBUTE_FIELD);
+ }
+ }, [selectedNode?.kind]);
return (
<>
- {
+ const [open, setOpen] = useState(false);
+
+ return (
+
+
+
+
+
+
+ {selectedNode && (
+
+ {selectedNode.label} {selectedNode.namespace}
+
+ )}
+
+
+
+
+
+ {nodesWithNumberAttributes.map((node) => (
+ {
+ const newValue = node.kind === selectedNode?.kind ? null : node.kind;
+ field.onChange(
+ updateFormFieldValue(newValue ?? null, DEFAULT_FORM_FIELD_VALUE)
+ );
+
+ setOpen(false);
+ }}
+ >
+
+ {node.label} {node.namespace}
+
+
+ ))}
+
+
+
+
+
+
+ );
+ }}
/>
- {
+ const [open, setOpen] = useState(false);
+ const selectedAttribute: FormFieldValue = field.value;
+
+ return (
+
+
+
+
+
+
+ {
+ numberAttributeOptions.find(
+ (attribute) => attribute.name === selectedAttribute?.value
+ )?.label
+ }
+
+
+
+
+
+ {numberAttributeOptions.map((attribute) => (
+ {
+ const newValue =
+ attribute.name === selectedNode?.name ? null : attribute.name;
+ field.onChange(updateFormFieldValue(newValue, DEFAULT_FORM_FIELD_VALUE));
+ setOpen(false);
+ }}
+ >
+ {attribute.label}
+
+ ))}
+
+
+
+
+
+
+ );
+ }}
/>
>
);
diff --git a/frontend/app/src/screens/resource-manager/resource-selector.tsx b/frontend/app/src/screens/resource-manager/resource-selector.tsx
index 67351aa5c7..29712398a4 100644
--- a/frontend/app/src/screens/resource-manager/resource-selector.tsx
+++ b/frontend/app/src/screens/resource-manager/resource-selector.tsx
@@ -35,7 +35,8 @@ const ResourceSelector = ({ resources, className, ...props }: ResourcePoolSelect
name: (
+ className="font-semibold underline"
+ >
{resource.display_label}
),
@@ -49,7 +50,8 @@ const ResourceSelector = ({ resources, className, ...props }: ResourcePoolSelect
+ className="flex items-center gap-1 text-nowrap hover:underline"
+ >
View
diff --git a/frontend/app/src/screens/role-management/account-form.tsx b/frontend/app/src/screens/role-management/account-form.tsx
new file mode 100644
index 0000000000..6335ce70b1
--- /dev/null
+++ b/frontend/app/src/screens/role-management/account-form.tsx
@@ -0,0 +1,151 @@
+import { Button } from "@/components/buttons/button-primitive";
+import { NodeFormProps } from "@/components/form/node-form";
+import { FormFieldValue } from "@/components/form/type";
+import { getCurrentFieldValue } from "@/components/form/utils/getFieldDefaultValue";
+import { getCreateMutationFromFormDataOnly } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { Form, FormSubmit } from "@/components/ui/form";
+import { ACCOUNT_GROUP_OBJECT, ACCOUNT_OBJECT, OBJECT_PERMISSION_OBJECT } from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { createObject } from "@/graphql/mutations/objects/createObject";
+import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { currentBranchAtom } from "@/state/atoms/branches.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
+import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { stringifyWithoutQuotes } from "@/utils/string";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { FieldValues, useForm } from "react-hook-form";
+import { toast } from "react-toastify";
+
+import InputField from "@/components/form/fields/input.field";
+import RelationshipField from "@/components/form/fields/relationship.field";
+import { isRequired } from "@/components/form/utils/validation";
+import { useSchema } from "@/hooks/useSchema";
+
+interface NumberPoolFormProps extends Pick {
+ currentObject?: Record;
+ onCancel?: () => void;
+ onUpdateComplete?: () => void;
+}
+
+export const AccountForm = ({
+ currentObject,
+ onSuccess,
+ onCancel,
+ onUpdateComplete,
+}: NumberPoolFormProps) => {
+ const branch = useAtomValue(currentBranchAtom);
+ const date = useAtomValue(datetimeAtom);
+ const { schema } = useSchema(ACCOUNT_OBJECT);
+
+ const defaultValues = {
+ name: getCurrentFieldValue("name", currentObject),
+ password: getCurrentFieldValue("password", currentObject),
+ description: getCurrentFieldValue("description", currentObject),
+ label: getCurrentFieldValue("label", currentObject),
+ groups: getCurrentFieldValue("groups", currentObject),
+ };
+
+ const form = useForm({
+ defaultValues,
+ });
+
+ async function handleSubmit(data: Record) {
+ try {
+ const newObject = getCreateMutationFromFormDataOnly(data, currentObject);
+
+ if (!Object.keys(newObject).length) {
+ return;
+ }
+
+ const mutationString = currentObject
+ ? updateObjectWithId({
+ kind: ACCOUNT_OBJECT,
+ data: stringifyWithoutQuotes({
+ id: currentObject.id,
+ ...newObject,
+ }),
+ })
+ : createObject({
+ kind: ACCOUNT_OBJECT,
+ data: stringifyWithoutQuotes({
+ ...newObject,
+ }),
+ });
+
+ const mutation = gql`
+ ${mutationString}
+ `;
+
+ const result = await graphqlClient.mutate({
+ mutation,
+ context: {
+ branch: branch?.name,
+ date,
+ },
+ });
+
+ toast(, {
+ toastId: "alert-success-account-created",
+ });
+
+ if (onSuccess) await onSuccess(result?.data?.[`${OBJECT_PERMISSION_OBJECT}Create`]);
+ if (onUpdateComplete) await onUpdateComplete();
+ } catch (error: unknown) {
+ console.error("An error occurred while creating the object: ", error);
+ }
+ }
+
+ return (
+
+ );
+};
diff --git a/frontend/app/src/screens/role-management/account-group-form.tsx b/frontend/app/src/screens/role-management/account-group-form.tsx
new file mode 100644
index 0000000000..f949e6a003
--- /dev/null
+++ b/frontend/app/src/screens/role-management/account-group-form.tsx
@@ -0,0 +1,167 @@
+import { Button } from "@/components/buttons/button-primitive";
+import { NodeFormProps } from "@/components/form/node-form";
+import { FormFieldValue } from "@/components/form/type";
+import { getCurrentFieldValue } from "@/components/form/utils/getFieldDefaultValue";
+import { getCreateMutationFromFormDataOnly } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { Form, FormSubmit } from "@/components/ui/form";
+import {
+ ACCOUNT_GROUP_OBJECT,
+ ACCOUNT_OBJECT,
+ ACCOUNT_ROLE_OBJECT,
+ OBJECT_PERMISSION_OBJECT,
+} from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { createObject } from "@/graphql/mutations/objects/createObject";
+import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { currentBranchAtom } from "@/state/atoms/branches.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
+import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { stringifyWithoutQuotes } from "@/utils/string";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { FieldValues, useForm } from "react-hook-form";
+import { toast } from "react-toastify";
+
+import DropdownField from "@/components/form/fields/dropdown.field";
+import InputField from "@/components/form/fields/input.field";
+import RelationshipField from "@/components/form/fields/relationship.field";
+import { isRequired } from "@/components/form/utils/validation";
+import { DropdownOption } from "@/components/inputs/dropdown";
+import { useSchema } from "@/hooks/useSchema";
+
+interface NumberPoolFormProps extends Pick {
+ currentObject?: Record;
+ onCancel?: () => void;
+ onUpdateComplete?: () => void;
+}
+
+export const AccountGroupForm = ({
+ currentObject,
+ onSuccess,
+ onCancel,
+ onUpdateComplete,
+}: NumberPoolFormProps) => {
+ const branch = useAtomValue(currentBranchAtom);
+ const date = useAtomValue(datetimeAtom);
+ const { schema } = useSchema(ACCOUNT_GROUP_OBJECT);
+
+ const defaultValues = {
+ name: getCurrentFieldValue("name", currentObject),
+ description: getCurrentFieldValue("description", currentObject),
+ label: getCurrentFieldValue("label", currentObject),
+ group_type: getCurrentFieldValue("group_type", currentObject),
+ roles: getCurrentFieldValue("roles", currentObject),
+ accounts: getCurrentFieldValue("accounts", currentObject),
+ };
+
+ const form = useForm({
+ defaultValues,
+ });
+
+ async function handleSubmit(data: Record) {
+ try {
+ const newObject = getCreateMutationFromFormDataOnly(data, currentObject);
+
+ if (!Object.keys(newObject).length) {
+ return;
+ }
+
+ const mutationString = currentObject
+ ? updateObjectWithId({
+ kind: ACCOUNT_GROUP_OBJECT,
+ data: stringifyWithoutQuotes({
+ id: currentObject.id,
+ ...newObject,
+ }),
+ })
+ : createObject({
+ kind: ACCOUNT_GROUP_OBJECT,
+ data: stringifyWithoutQuotes({
+ ...newObject,
+ }),
+ });
+
+ const mutation = gql`
+ ${mutationString}
+ `;
+
+ const result = await graphqlClient.mutate({
+ mutation,
+ context: {
+ branch: branch?.name,
+ date,
+ },
+ });
+
+ toast(, {
+ toastId: "alert-success-group-created",
+ });
+
+ if (onSuccess) await onSuccess(result?.data?.[`${OBJECT_PERMISSION_OBJECT}Create`]);
+ if (onUpdateComplete) await onUpdateComplete();
+ } catch (error: unknown) {
+ console.error("An error occurred while creating the object: ", error);
+ }
+ }
+
+ const typeOptions: DropdownOption[] =
+ schema?.attributes
+ ?.find((attribute) => attribute.name === "group_type")
+ ?.enum?.map((data) => ({ value: data as string, label: data as string })) ?? [];
+
+ return (
+
+ );
+};
diff --git a/frontend/app/src/screens/role-management/account-role-form.tsx b/frontend/app/src/screens/role-management/account-role-form.tsx
new file mode 100644
index 0000000000..ca250d78a7
--- /dev/null
+++ b/frontend/app/src/screens/role-management/account-role-form.tsx
@@ -0,0 +1,146 @@
+import { Button } from "@/components/buttons/button-primitive";
+import { NodeFormProps } from "@/components/form/node-form";
+import { FormFieldValue } from "@/components/form/type";
+import { getCurrentFieldValue } from "@/components/form/utils/getFieldDefaultValue";
+import { getCreateMutationFromFormDataOnly } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { Form, FormSubmit } from "@/components/ui/form";
+import {
+ ACCOUNT_GROUP_OBJECT,
+ ACCOUNT_PERMISSION_OBJECT,
+ ACCOUNT_ROLE_OBJECT,
+} from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { createObject } from "@/graphql/mutations/objects/createObject";
+import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { currentBranchAtom } from "@/state/atoms/branches.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
+import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { stringifyWithoutQuotes } from "@/utils/string";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { FieldValues, useForm } from "react-hook-form";
+import { toast } from "react-toastify";
+
+import InputField from "@/components/form/fields/input.field";
+import RelationshipField from "@/components/form/fields/relationship.field";
+import { isRequired } from "@/components/form/utils/validation";
+
+interface NumberPoolFormProps extends Pick {
+ currentObject?: Record;
+ onCancel?: () => void;
+ onUpdateComplete?: () => void;
+}
+
+export const AccountRoleForm = ({
+ currentObject,
+ onSuccess,
+ onCancel,
+ onUpdateComplete,
+}: NumberPoolFormProps) => {
+ const branch = useAtomValue(currentBranchAtom);
+ const date = useAtomValue(datetimeAtom);
+
+ const defaultValues = {
+ name: getCurrentFieldValue("name", currentObject),
+ group: getCurrentFieldValue("group", currentObject),
+ permissions: getCurrentFieldValue("permissions", currentObject),
+ };
+
+ const form = useForm({
+ defaultValues,
+ });
+
+ async function handleSubmit(data: Record) {
+ try {
+ const newObject = getCreateMutationFromFormDataOnly(data, currentObject);
+
+ if (!Object.keys(newObject).length) {
+ return;
+ }
+
+ const mutationString = currentObject
+ ? updateObjectWithId({
+ kind: ACCOUNT_ROLE_OBJECT,
+ data: stringifyWithoutQuotes({
+ id: currentObject.id,
+ ...newObject,
+ }),
+ })
+ : createObject({
+ kind: ACCOUNT_ROLE_OBJECT,
+ data: stringifyWithoutQuotes({
+ ...newObject,
+ }),
+ });
+
+ const mutation = gql`
+ ${mutationString}
+ `;
+
+ const result = await graphqlClient.mutate({
+ mutation,
+ context: {
+ branch: branch?.name,
+ date,
+ },
+ });
+
+ toast(, {
+ toastId: "alert-success-role-created",
+ });
+
+ if (onSuccess) await onSuccess(result?.data?.[`${ACCOUNT_ROLE_OBJECT}Create`]);
+ if (onUpdateComplete) await onUpdateComplete();
+ } catch (error: unknown) {
+ console.error("An error occurred while creating the object: ", error);
+ }
+ }
+
+ return (
+
+ );
+};
diff --git a/frontend/app/src/screens/role-management/accounts.tsx b/frontend/app/src/screens/role-management/accounts.tsx
new file mode 100644
index 0000000000..99162c3c70
--- /dev/null
+++ b/frontend/app/src/screens/role-management/accounts.tsx
@@ -0,0 +1,140 @@
+import { Button } from "@/components/buttons/button-primitive";
+import { ColorDisplay } from "@/components/display/color-display";
+import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import ObjectForm from "@/components/form/object-form";
+import ModalDeleteObject from "@/components/modals/modal-delete-object";
+import { Table } from "@/components/table/table";
+import { Pagination } from "@/components/ui/pagination";
+import { ACCOUNT_GENERIC_OBJECT, ACCOUNT_OBJECT } from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { GET_ROLE_MANAGEMENT_ACCOUNTS } from "@/graphql/queries/role-management/getAccounts";
+import { useSchema } from "@/hooks/useSchema";
+import { schemaKindNameState } from "@/state/atoms/schemaKindName.atom";
+import { useQuery } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { useState } from "react";
+import ErrorScreen from "../errors/error-screen";
+import LoadingScreen from "../loading-screen/loading-screen";
+
+function Accounts() {
+ const { loading, data, error, refetch } = useQuery(GET_ROLE_MANAGEMENT_ACCOUNTS);
+ const schemaKindName = useAtomValue(schemaKindNameState);
+ const { schema } = useSchema(ACCOUNT_GENERIC_OBJECT);
+
+ const [rowToDelete, setRowToDelete] = useState(null);
+ const [showCreateDrawer, setShowCreateDrawer] = useState(false);
+
+ const columns = [
+ {
+ name: "display_label",
+ label: "Name",
+ },
+ {
+ name: "description",
+ label: "Description",
+ },
+ {
+ name: "account_type",
+ label: "Type",
+ },
+ {
+ name: "status",
+ label: "Status",
+ },
+ ];
+
+ const rows =
+ data &&
+ data[ACCOUNT_GENERIC_OBJECT]?.edges.map((edge) => ({
+ values: {
+ id: edge?.node?.id,
+ display_label: edge?.node?.display_label,
+ description: edge?.node?.description?.value,
+ account_type: edge?.node?.account_type?.value,
+ status: (
+
+ ),
+ __typename: edge?.node?.__typename,
+ },
+ }));
+
+ if (error) return ;
+
+ if (loading) return ;
+
+ const globalRefetch = () => {
+ graphqlClient.refetchQueries({ include: ["GET_ROLE_MANAGEMENT_COUNTS"] });
+ refetch();
+ };
+
+ return (
+ <>
+
+
+
{/* Search input + filter button */}
+
+
+ setShowCreateDrawer(true)}
+ disabled={!schema}
+ >
+ Create {schema?.label}
+
+
+
+
+
setRowToDelete(data.values)}
+ />
+
+
+
+
+ {
+ setRowToDelete(null);
+ }}
+ onDelete={() => globalRefetch()}
+ />
+
+ {schema && (
+
+ }
+ open={showCreateDrawer}
+ setOpen={(value) => setShowCreateDrawer(value)}
+ >
+ setShowCreateDrawer(false)}
+ onSuccess={() => {
+ setShowCreateDrawer(false);
+ globalRefetch();
+ }}
+ />
+
+ )}
+ >
+ );
+}
+
+export function Component() {
+ return ;
+}
diff --git a/frontend/app/src/screens/role-management/global-permissions.tsx b/frontend/app/src/screens/role-management/global-permissions.tsx
new file mode 100644
index 0000000000..83f8920dfe
--- /dev/null
+++ b/frontend/app/src/screens/role-management/global-permissions.tsx
@@ -0,0 +1,78 @@
+import { Pill } from "@/components/display/pill";
+import { Table } from "@/components/table/table";
+import { BadgeCopy } from "@/components/ui/badge-copy";
+import { Pagination } from "@/components/ui/pagination";
+import { GLOBAL_PERMISSION_OBJECT } from "@/config/constants";
+import { GET_ROLE_MANAGEMENT_GLOBAL_PERMISSIONS } from "@/graphql/queries/role-management/getGlobalPermissions";
+import { useQuery } from "@apollo/client";
+import { Icon } from "@iconify-icon/react";
+import ErrorScreen from "../errors/error-screen";
+import LoadingScreen from "../loading-screen/loading-screen";
+
+function GlobalPermissions() {
+ const { loading, data, error } = useQuery(GET_ROLE_MANAGEMENT_GLOBAL_PERMISSIONS);
+
+ const columns = [
+ {
+ name: "name",
+ label: "Name",
+ },
+ {
+ name: "action",
+ label: "Action",
+ },
+ {
+ name: "roles",
+ label: "Roles",
+ },
+ {
+ name: "identifier",
+ label: "Identifier",
+ },
+ ];
+
+ const rows =
+ data &&
+ data[GLOBAL_PERMISSION_OBJECT]?.edges.map((edge) => {
+ return {
+ id: edge?.node?.id,
+ values: {
+ display_label: edge?.node?.display_label,
+ name: (
+
+
+
+
+
+ {edge?.node?.display_label}
+
+ ),
+ description: edge?.node?.description?.value,
+ roles: {edge?.node?.roles?.count},
+ identifier: ,
+ },
+ };
+ });
+
+ if (error) return ;
+
+ if (loading) return ;
+
+ return (
+ <>
+
+
+
{/* Search input + filter button */}
+
+
+
+
+
+
+ >
+ );
+}
+
+export function Component() {
+ return ;
+}
diff --git a/frontend/app/src/screens/role-management/group-member.tsx b/frontend/app/src/screens/role-management/group-member.tsx
new file mode 100644
index 0000000000..2be6b8dffd
--- /dev/null
+++ b/frontend/app/src/screens/role-management/group-member.tsx
@@ -0,0 +1,33 @@
+import { Avatar } from "@/components/display/avatar";
+import { Tooltip } from "@/components/ui/tooltip";
+
+interface GroupMembersProps {
+ members: Array;
+}
+
+export function GroupMembers({ members }: GroupMembersProps) {
+ const trimedMembers = members.slice(0, 5);
+
+ const lengthDiff = members.length - trimedMembers.length;
+
+ return (
+
+
+ {trimedMembers.map((member, index) => (
+
+
+
+ ))}
+
+
+ {!!lengthDiff && (
+
+ )}
+
+ );
+}
diff --git a/frontend/app/src/screens/role-management/groups.tsx b/frontend/app/src/screens/role-management/groups.tsx
new file mode 100644
index 0000000000..c5537500f0
--- /dev/null
+++ b/frontend/app/src/screens/role-management/groups.tsx
@@ -0,0 +1,136 @@
+import { Button } from "@/components/buttons/button-primitive";
+import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import ObjectForm from "@/components/form/object-form";
+import ModalDeleteObject from "@/components/modals/modal-delete-object";
+import { Table } from "@/components/table/table";
+import { Pagination } from "@/components/ui/pagination";
+import { ACCOUNT_GROUP_OBJECT } from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { GET_ROLE_MANAGEMENT_GROUPS } from "@/graphql/queries/role-management/getGroups";
+import { useSchema } from "@/hooks/useSchema";
+import { schemaKindNameState } from "@/state/atoms/schemaKindName.atom";
+import { useQuery } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { useState } from "react";
+import ErrorScreen from "../errors/error-screen";
+import LoadingScreen from "../loading-screen/loading-screen";
+import { GroupMembers } from "./group-member";
+
+function Groups() {
+ const { loading, data, error, refetch } = useQuery(GET_ROLE_MANAGEMENT_GROUPS);
+ const schemaKindName = useAtomValue(schemaKindNameState);
+ const { schema } = useSchema(ACCOUNT_GROUP_OBJECT);
+ const [rowToDelete, setRowToDelete] = useState(null);
+ const [showCreateDrawer, setShowCreateDrawer] = useState(false);
+
+ const columns = [
+ {
+ name: "display_label",
+ label: "Name",
+ },
+ {
+ name: "description",
+ label: "Description",
+ },
+ {
+ name: "account_type",
+ label: "Type",
+ },
+ {
+ name: "members",
+ label: "Members",
+ },
+ ];
+
+ const rows =
+ data &&
+ data[ACCOUNT_GROUP_OBJECT]?.edges.map((edge) => ({
+ id: edge?.node?.id,
+ values: {
+ id: edge?.node?.id,
+ display_label: edge?.node?.display_label,
+ description: edge?.node?.description?.value,
+ group_type: edge?.node?.group_type?.value,
+ members: (
+ edge?.node?.display_label) ?? []}
+ />
+ ),
+ __typename: edge?.node?.__typename,
+ },
+ }));
+
+ if (error) return ;
+
+ if (loading) return ;
+
+ const globalRefetch = () => {
+ graphqlClient.refetchQueries({ include: ["GET_ROLE_MANAGEMENT_COUNTS"] });
+ refetch();
+ };
+
+ return (
+ <>
+
+
+
{/* Search input + filter button */}
+
+
+ setShowCreateDrawer(true)}
+ disabled={!schema}
+ >
+ Create {schema?.label}
+
+
+
+
+
setRowToDelete(data.values)}
+ />
+
+
+
+
+ setRowToDelete(null)}
+ onDelete={() => globalRefetch()}
+ />
+
+ {schema && (
+
+ }
+ open={showCreateDrawer}
+ setOpen={(value) => setShowCreateDrawer(value)}
+ >
+ setShowCreateDrawer(false)}
+ onSuccess={() => {
+ setShowCreateDrawer(false);
+ globalRefetch();
+ }}
+ />
+
+ )}
+ >
+ );
+}
+
+export function Component() {
+ return ;
+}
diff --git a/frontend/app/src/screens/role-management/index.tsx b/frontend/app/src/screens/role-management/index.tsx
new file mode 100644
index 0000000000..4a4f9cbdef
--- /dev/null
+++ b/frontend/app/src/screens/role-management/index.tsx
@@ -0,0 +1,86 @@
+import { Tabs } from "@/components/tabs-routes";
+import {
+ ACCOUNT_GENERIC_OBJECT,
+ ACCOUNT_GROUP_OBJECT,
+ ACCOUNT_ROLE_OBJECT,
+ GLOBAL_PERMISSION_OBJECT,
+ OBJECT_PERMISSION_OBJECT,
+} from "@/config/constants";
+import { GET_ROLE_MANAGEMENT_COUNTS } from "@/graphql/queries/role-management/getCounts";
+import useQuery from "@/hooks/useQuery";
+
+import { constructPath } from "@/utils/fetch";
+import { Icon } from "@iconify-icon/react";
+
+export function RoleManagementNavigation() {
+ const { loading, data, error } = useQuery(GET_ROLE_MANAGEMENT_COUNTS);
+
+ const tabs = [
+ {
+ to: constructPath("/role-management"),
+ label: (
+
+
+ Accounts
+
+ ),
+ count: data && data[ACCOUNT_GENERIC_OBJECT]?.count,
+ isLoading: loading,
+ error: !!error,
+ },
+ {
+ to: constructPath("/role-management/groups"),
+ label: (
+
+
+ Groups
+
+ ),
+ count: data && data[ACCOUNT_GROUP_OBJECT]?.count,
+ isLoading: loading,
+ error: !!error,
+ },
+ {
+ to: constructPath("/role-management/roles"),
+ label: (
+
+
+ Roles
+
+ ),
+ count: data && data[ACCOUNT_ROLE_OBJECT]?.count,
+ isLoading: loading,
+ error: !!error,
+ },
+ {
+ to: constructPath("/role-management/global-permissions"),
+ label: (
+
+
+ Global Permissions
+
+ ),
+ count: data && data[GLOBAL_PERMISSION_OBJECT]?.count,
+ isLoading: loading,
+ error: !!error,
+ },
+ {
+ to: constructPath("/role-management/object-permissions"),
+ label: (
+
+
+ Object Permissions
+
+ ),
+ count: data && data[OBJECT_PERMISSION_OBJECT]?.count,
+ isLoading: loading,
+ error: !!error,
+ },
+ ];
+
+ return (
+
+
+
+ );
+}
diff --git a/frontend/app/src/screens/role-management/object-permissions-form.tsx b/frontend/app/src/screens/role-management/object-permissions-form.tsx
new file mode 100644
index 0000000000..dba52ed164
--- /dev/null
+++ b/frontend/app/src/screens/role-management/object-permissions-form.tsx
@@ -0,0 +1,238 @@
+import { Button } from "@/components/buttons/button-primitive";
+import { NodeFormProps } from "@/components/form/node-form";
+import { FormAttributeValue, FormFieldValue } from "@/components/form/type";
+import { getCurrentFieldValue } from "@/components/form/utils/getFieldDefaultValue";
+import { getCreateMutationFromFormDataOnly } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
+import { ALERT_TYPES, Alert } from "@/components/ui/alert";
+import { Form, FormSubmit } from "@/components/ui/form";
+import { ACCOUNT_ROLE_OBJECT, OBJECT_PERMISSION_OBJECT } from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { createObject } from "@/graphql/mutations/objects/createObject";
+import { updateObjectWithId } from "@/graphql/mutations/objects/updateObjectWithId";
+import { branchesState, currentBranchAtom } from "@/state/atoms/branches.atom";
+import { namespacesState, schemaState } from "@/state/atoms/schema.atom";
+import { datetimeAtom } from "@/state/atoms/time.atom";
+import { AttributeType, RelationshipType } from "@/utils/getObjectItemDisplayValue";
+import { stringifyWithoutQuotes } from "@/utils/string";
+import { gql } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { FieldValues, useForm, useFormContext } from "react-hook-form";
+import { toast } from "react-toastify";
+
+import { DEFAULT_FORM_FIELD_VALUE } from "@/components/form/constants";
+import DropdownField from "@/components/form/fields/dropdown.field";
+import RelationshipField from "@/components/form/fields/relationship.field";
+import { isRequired } from "@/components/form/utils/validation";
+
+interface NumberPoolFormProps extends Pick {
+ currentObject?: Record;
+ onCancel?: () => void;
+ onUpdateComplete?: () => void;
+}
+
+export const ObjectPermissionForm = ({
+ currentObject,
+ onSuccess,
+ onCancel,
+ onUpdateComplete,
+}: NumberPoolFormProps) => {
+ const branches = useAtomValue(branchesState);
+ const branch = useAtomValue(currentBranchAtom);
+ const date = useAtomValue(datetimeAtom);
+
+ const defaultValues = {
+ branch: getCurrentFieldValue("branch", currentObject),
+ namespace: getCurrentFieldValue("namespace", currentObject),
+ name: getCurrentFieldValue("name", currentObject),
+ roles: getCurrentFieldValue("roles", currentObject),
+ };
+
+ const form = useForm({
+ defaultValues,
+ });
+
+ const branchesOptions = branches.map((branch) => ({ value: branch.name, label: branch.name }));
+
+ const actionOptions = [
+ {
+ value: "view",
+ label: "View",
+ },
+ {
+ value: "create",
+ label: "Create",
+ },
+ {
+ value: "update",
+ label: "Update",
+ },
+ {
+ value: "delete",
+ label: "Delete",
+ },
+ ];
+
+ const decisionOptions = [
+ {
+ value: "allow",
+ label: "Allow",
+ },
+ {
+ value: "deny",
+ label: "Deny",
+ },
+ ];
+
+ async function handleSubmit(data: Record) {
+ try {
+ const newObject = getCreateMutationFromFormDataOnly(data, currentObject);
+
+ if (!Object.keys(newObject).length) {
+ return;
+ }
+
+ const mutationString = currentObject
+ ? updateObjectWithId({
+ kind: OBJECT_PERMISSION_OBJECT,
+ data: stringifyWithoutQuotes({
+ id: currentObject.id,
+ ...newObject,
+ }),
+ })
+ : createObject({
+ kind: OBJECT_PERMISSION_OBJECT,
+ data: stringifyWithoutQuotes({
+ ...newObject,
+ }),
+ });
+
+ const mutation = gql`
+ ${mutationString}
+ `;
+
+ const result = await graphqlClient.mutate({
+ mutation,
+ context: {
+ branch: branch?.name,
+ date,
+ },
+ });
+
+ toast(, {
+ toastId: "alert-success-object-permission-created",
+ });
+
+ if (onSuccess) await onSuccess(result?.data?.[`${OBJECT_PERMISSION_OBJECT}Create`]);
+ if (onUpdateComplete) await onUpdateComplete();
+ } catch (error: unknown) {
+ console.error("An error occurred while creating the object: ", error);
+ }
+ }
+
+ return (
+
+ );
+};
+
+const NodeSelect = () => {
+ const namespaces = useAtomValue(namespacesState);
+ const nodes = useAtomValue(schemaState);
+
+ const form = useFormContext();
+ const selectedNamespaceField: FormAttributeValue = form.watch("namespace");
+
+ const namespaceOptions = [
+ {
+ value: "*",
+ label: "*",
+ },
+ ...namespaces.map((namespace) => ({
+ value: namespace.name,
+ label: namespace.name,
+ })),
+ ];
+
+ const selectedNamespace =
+ selectedNamespaceField?.value === "*"
+ ? { value: "*", name: "*" }
+ : namespaces.find((namespace) => namespace.name === selectedNamespaceField?.value);
+
+ const nameOptions = [
+ {
+ value: "*",
+ label: "*",
+ },
+ ...nodes
+ .filter((node) => node.namespace === selectedNamespace?.name)
+ .map((node) => ({
+ value: node.name,
+ label: node.label,
+ })),
+ ];
+
+ return (
+ <>
+
+
+
+ >
+ );
+};
diff --git a/frontend/app/src/screens/role-management/object-permissions.tsx b/frontend/app/src/screens/role-management/object-permissions.tsx
new file mode 100644
index 0000000000..dabc22ebe2
--- /dev/null
+++ b/frontend/app/src/screens/role-management/object-permissions.tsx
@@ -0,0 +1,175 @@
+import { Button } from "@/components/buttons/button-primitive";
+import { Pill } from "@/components/display/pill";
+import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import ObjectForm from "@/components/form/object-form";
+import ModalDeleteObject from "@/components/modals/modal-delete-object";
+import { Table } from "@/components/table/table";
+import { BadgeCopy } from "@/components/ui/badge-copy";
+import { Pagination } from "@/components/ui/pagination";
+import { OBJECT_PERMISSION_OBJECT } from "@/config/constants";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { GET_ROLE_MANAGEMENT_OBJECT_PERMISSIONS } from "@/graphql/queries/role-management/getObjectPermissions";
+import { useSchema } from "@/hooks/useSchema";
+import { schemaKindNameState } from "@/state/atoms/schemaKindName.atom";
+import { useQuery } from "@apollo/client";
+import { Icon } from "@iconify-icon/react";
+import { useAtomValue } from "jotai";
+import { ReactNode, useState } from "react";
+import ErrorScreen from "../errors/error-screen";
+import LoadingScreen from "../loading-screen/loading-screen";
+
+const icons: Record = {
+ allow: (
+
+
+
+ ),
+ deny: (
+
+
+
+ ),
+};
+
+function Permissions() {
+ const { loading, data, error, refetch } = useQuery(GET_ROLE_MANAGEMENT_OBJECT_PERMISSIONS);
+ const schemaKindName = useAtomValue(schemaKindNameState);
+ const { schema } = useSchema(OBJECT_PERMISSION_OBJECT);
+ const [rowToDelete, setRowToDelete] = useState(null);
+ const [showCreateDrawer, setShowCreateDrawer] = useState(false);
+
+ const columns = [
+ {
+ name: "display_label",
+ label: "Name",
+ },
+ {
+ name: "branch",
+ label: "Branch",
+ },
+ {
+ name: "namespace",
+ label: "Namespace",
+ },
+ {
+ name: "name",
+ label: "Node",
+ },
+ {
+ name: "action",
+ label: "Action",
+ },
+ {
+ name: "decision",
+ label: "Decision",
+ },
+ {
+ name: "roles",
+ label: "Roles",
+ },
+ {
+ name: "identifier",
+ label: "Identifier",
+ },
+ ];
+
+ const rows =
+ data &&
+ data[OBJECT_PERMISSION_OBJECT]?.edges.map((edge) => {
+ const iconKey = edge?.node?.decision?.value;
+ const icon = icons[iconKey];
+
+ return {
+ values: {
+ id: edge?.node?.id,
+ display_label: (
+
+ {icon} {edge?.node?.display_label}
+
+ ),
+ branch: edge?.node?.branch?.value,
+ namespace: edge?.node?.namespace?.value,
+ name: edge?.node?.name?.value,
+ action: edge?.node?.action?.value,
+ decision: edge?.node?.decision?.value,
+ roles: {edge?.node?.roles?.count},
+ identifier: ,
+ __typename: edge?.node?.__typename,
+ },
+ };
+ });
+
+ if (error) return ;
+
+ if (loading) return ;
+
+ const globalRefetch = () => {
+ graphqlClient.refetchQueries({ include: ["GET_ROLE_MANAGEMENT_COUNTS"] });
+ refetch();
+ };
+
+ return (
+ <>
+
+
+
{/* Search input + filter button */}
+
+
+ setShowCreateDrawer(true)}
+ disabled={!schema}
+ >
+ Create {schema?.label}
+
+
+
+
+
setRowToDelete(data.values)}
+ />
+
+
+
+
+ setRowToDelete(null)}
+ onDelete={() => globalRefetch()}
+ />
+
+ {schema && (
+
+ }
+ open={showCreateDrawer}
+ setOpen={(value) => setShowCreateDrawer(value)}
+ >
+ setShowCreateDrawer(false)}
+ onSuccess={() => {
+ setShowCreateDrawer(false);
+ globalRefetch();
+ }}
+ />
+
+ )}
+ >
+ );
+}
+
+export function Component() {
+ return ;
+}
diff --git a/frontend/app/src/screens/role-management/roles.tsx b/frontend/app/src/screens/role-management/roles.tsx
new file mode 100644
index 0000000000..1965068b54
--- /dev/null
+++ b/frontend/app/src/screens/role-management/roles.tsx
@@ -0,0 +1,132 @@
+import { Pill } from "@/components/display/pill";
+import ModalDeleteObject from "@/components/modals/modal-delete-object";
+import { Table } from "@/components/table/table";
+import { Pagination } from "@/components/ui/pagination";
+import { ACCOUNT_ROLE_OBJECT } from "@/config/constants";
+import { GET_ROLE_MANAGEMENT_ROLES } from "@/graphql/queries/role-management/getRoles";
+import { schemaKindNameState } from "@/state/atoms/schemaKindName.atom";
+import { useQuery } from "@apollo/client";
+import { useAtomValue } from "jotai";
+import { useState } from "react";
+import ErrorScreen from "../errors/error-screen";
+import LoadingScreen from "../loading-screen/loading-screen";
+
+import { Button } from "@/components/buttons/button-primitive";
+import SlideOver, { SlideOverTitle } from "@/components/display/slide-over";
+import ObjectForm from "@/components/form/object-form";
+import graphqlClient from "@/graphql/graphqlClientApollo";
+import { useSchema } from "@/hooks/useSchema";
+
+function Roles() {
+ const { loading, data, error, refetch } = useQuery(GET_ROLE_MANAGEMENT_ROLES);
+ const schemaKindName = useAtomValue(schemaKindNameState);
+ const { schema } = useSchema(ACCOUNT_ROLE_OBJECT);
+ const [rowToDelete, setRowToDelete] = useState(null);
+ const [showCreateDrawer, setShowCreateDrawer] = useState(false);
+
+ const columns = [
+ {
+ name: "display_label",
+ label: "Name",
+ },
+ {
+ name: "description",
+ label: "Description",
+ },
+ {
+ name: "groups",
+ label: "Groups",
+ },
+ {
+ name: "permissions",
+ label: "Permissions",
+ },
+ ];
+
+ const rows =
+ data &&
+ data[ACCOUNT_ROLE_OBJECT]?.edges.map((edge) => ({
+ values: {
+ id: edge?.node?.id,
+ display_label: edge?.node?.display_label,
+ description: edge?.node?.description?.value,
+ groups: {edge?.node?.groups?.count},
+ permissions: {edge?.node?.permissions?.count},
+ __typename: edge?.node?.__typename,
+ },
+ }));
+
+ if (error) return ;
+
+ if (loading) return ;
+
+ const globalRefetch = () => {
+ graphqlClient.refetchQueries({ include: ["GET_ROLE_MANAGEMENT_COUNTS"] });
+ refetch();
+ };
+
+ return (
+ <>
+
+
+
{/* Search input + filter button */}
+
+
+ setShowCreateDrawer(true)}
+ disabled={!schema}
+ >
+ Create {schema?.label}
+
+
+
+
+
setRowToDelete(data.values)}
+ />
+
+
+
+
+ setRowToDelete(null)}
+ onDelete={() => globalRefetch()}
+ />
+
+ {schema && (
+
+ }
+ open={showCreateDrawer}
+ setOpen={(value) => setShowCreateDrawer(value)}
+ >
+ setShowCreateDrawer(false)}
+ onSuccess={() => {
+ setShowCreateDrawer(false);
+ globalRefetch();
+ }}
+ />
+
+ )}
+ >
+ );
+}
+
+export function Component() {
+ return ;
+}
diff --git a/frontend/app/src/screens/schema/attribute-display.tsx b/frontend/app/src/screens/schema/attribute-display.tsx
index 6e7c20b4b4..2ad7b7ea66 100644
--- a/frontend/app/src/screens/schema/attribute-display.tsx
+++ b/frontend/app/src/screens/schema/attribute-display.tsx
@@ -13,7 +13,8 @@ export const AttributeDisplay = ({
description={attribute.description}
isOptional={attribute.optional}
isUnique={attribute.unique}
- isReadOnly={attribute.read_only}>
+ isReadOnly={attribute.read_only}
+ >
@@ -65,7 +66,8 @@ const ChoicesRow = ({
}
className="px-1.5 py-0.5 rounded-md flex-grow divide-y divide-gray-600"
- style={{ backgroundColor: color ?? undefined }}>
+ style={{ backgroundColor: color ?? undefined }}
+ >
diff --git a/frontend/app/src/screens/schema/relationship-display.tsx b/frontend/app/src/screens/schema/relationship-display.tsx
index 872be6f518..cfb990559f 100644
--- a/frontend/app/src/screens/schema/relationship-display.tsx
+++ b/frontend/app/src/screens/schema/relationship-display.tsx
@@ -31,7 +31,8 @@ export const RelationshipDisplay = ({
>
}
description={relationship.description}
- isOptional={relationship.optional}>
+ isOptional={relationship.optional}
+ >
diff --git a/frontend/app/src/screens/schema/schema-selector.tsx b/frontend/app/src/screens/schema/schema-selector.tsx
index 6a366c615a..bfcd0fd2e7 100644
--- a/frontend/app/src/screens/schema/schema-selector.tsx
+++ b/frontend/app/src/screens/schema/schema-selector.tsx
@@ -52,7 +52,8 @@ export const SchemaSelector = ({ className = "" }: SchemaSelectorProps) => {
hover:rounded
${isSelected ? "shadow-lg ring-1 ring-custom-blue-600 rounded" : ""}
`}
- onClick={() => setKind([schema.kind!])}>
+ onClick={() => setKind([schema.kind!])}
+ >
{schema.icon && (
diff --git a/frontend/app/src/screens/schema/schema-viewer.tsx b/frontend/app/src/screens/schema/schema-viewer.tsx
index 69eadbbafc..b69ff45810 100644
--- a/frontend/app/src/screens/schema/schema-viewer.tsx
+++ b/frontend/app/src/screens/schema/schema-viewer.tsx
@@ -70,7 +70,8 @@ export const SchemaViewer = ({
"flex flex-col overflow-hidden space-y-4 p-4 shadow-lg border border-gray-200 bg-custom-white rounded-md",
className
)}
- data-testid="schema-viewer">
+ data-testid="schema-viewer"
+ >
{schema.namespace}
diff --git a/frontend/app/src/screens/schema/styled.tsx b/frontend/app/src/screens/schema/styled.tsx
index 4d5a7295ea..121bf2fe2a 100644
--- a/frontend/app/src/screens/schema/styled.tsx
+++ b/frontend/app/src/screens/schema/styled.tsx
@@ -44,7 +44,8 @@ export const AccordionStyled = ({
}
className="bg-custom-white shadow p-3 rounded"
- {...props}>
+ {...props}
+ >
{children}
);
@@ -107,7 +108,8 @@ export const TabStyled = ({ children }: { children: ReactElement | string }) =>
"px-4 py-2 text-sm hover:bg-gray-100 focus:outline-none focus:bg-gray-100",
selected ? "border-b-2 border-b-custom-blue-600 font-semibold" : ""
)
- }>
+ }
+ >
{children}
);
@@ -135,7 +137,8 @@ export const ModelDisplay = ({ kinds }: { kinds?: string[] }) => {
className="bg-sky-50 text-sky-800 border-sky-200 hover:bg-sky-100 cursor-pointer"
onClick={() =>
setKinds(selectedKinds && selectedKinds?.length > 0 ? [...selectedKinds, kind] : [kind])
- }>
+ }
+ >
{kind}
))}
diff --git a/frontend/app/src/screens/tasks/task-item-details.tsx b/frontend/app/src/screens/tasks/task-item-details.tsx
index 88dc56be53..5c6d82d9cf 100644
--- a/frontend/app/src/screens/tasks/task-item-details.tsx
+++ b/frontend/app/src/screens/tasks/task-item-details.tsx
@@ -51,7 +51,7 @@ export const TaskItemDetails = forwardRef((props, ref) => {
return
;
}
- const result = data ? data[TASK_OBJECT] ?? {} : {};
+ const result = data ? (data[TASK_OBJECT] ?? {}) : {};
const { edges = [] } = result;
diff --git a/frontend/app/src/screens/tasks/task-items.tsx b/frontend/app/src/screens/tasks/task-items.tsx
index 255e3591dd..0aa7c1ce58 100644
--- a/frontend/app/src/screens/tasks/task-items.tsx
+++ b/frontend/app/src/screens/tasks/task-items.tsx
@@ -48,7 +48,7 @@ export const TaskItems = forwardRef(({ hideRelatedNode }: TaskItemsProps, ref) =
return
;
}
- const result = data ? data[TASK_OBJECT] ?? {} : {};
+ const result = data ? (data[TASK_OBJECT] ?? {}) : {};
const { count, edges = [] } = result;
diff --git a/frontend/app/src/screens/user-profile/tab-preferences.tsx b/frontend/app/src/screens/user-profile/tab-preferences.tsx
index 21e3b3e6bf..d6a7676032 100644
--- a/frontend/app/src/screens/user-profile/tab-preferences.tsx
+++ b/frontend/app/src/screens/user-profile/tab-preferences.tsx
@@ -1,12 +1,12 @@
+import PasswordInputField from "@/components/form/fields/password-input.field";
+import { isRequired } from "@/components/form/utils/validation";
import { ALERT_TYPES, Alert } from "@/components/ui/alert";
import { Card } from "@/components/ui/card";
+import { Form, FormSubmit } from "@/components/ui/form";
import { UPDATE_ACCOUNT_PASSWORD } from "@/graphql/mutations/accounts/updateAccountPassword";
+import { useMutation } from "@/hooks/useQuery";
import Content from "@/screens/layout/content";
import { toast } from "react-toastify";
-import { useMutation } from "@/hooks/useQuery";
-import { Form, FormSubmit } from "@/components/ui/form";
-import PasswordInputField from "@/components/form/fields/password-input.field";
-import { isRequired } from "@/components/form/utils/validation";
type UpdatePasswordFormData = {
newPassword: string;
@@ -38,7 +38,8 @@ export default function TabPreferences() {
confirmPassword: formData.confirmPassword.value as string,
};
await onSubmit(data);
- }}>
+ }}
+ >
kind === ACCOUNT_OBJECT);
+ const schema = nodes.find(({ kind }) => kind === ACCOUNT_GENERIC_OBJECT);
const localToken = localStorage.getItem(ACCESS_TOKEN_KEY);
const tokenData = parseJwt(localToken);
diff --git a/frontend/app/src/screens/user-profile/tab-tokens.tsx b/frontend/app/src/screens/user-profile/tab-tokens.tsx
index 746a891188..21722a85d5 100644
--- a/frontend/app/src/screens/user-profile/tab-tokens.tsx
+++ b/frontend/app/src/screens/user-profile/tab-tokens.tsx
@@ -1,14 +1,14 @@
import { Card } from "@/components/ui/card";
-import Content from "@/screens/layout/content";
import { ACCOUNT_TOKEN_OBJECT } from "@/config/constants";
-import { useAtomValue } from "jotai";
+import Content from "@/screens/layout/content";
import { schemaState } from "@/state/atoms/schema.atom";
-import ObjectItems from "../object-items/object-items-paginated";
-import LoadingScreen from "../loading-screen/loading-screen";
+import { useAtomValue } from "jotai";
import { useState } from "react";
+import LoadingScreen from "../loading-screen/loading-screen";
+import ObjectItems from "../object-items/object-items-paginated";
-import ModalSuccess from "@/components/modals/modal-success";
import { TokenInput } from "@/components/display/token-input";
+import ModalSuccess from "@/components/modals/modal-success";
export default function TabTokens() {
const [open, setOpen] = useState(false);
@@ -44,7 +44,8 @@ export default function TabTokens() {
You won't be able to see it again!
>
- }>
+ }
+ >
diff --git a/frontend/app/src/screens/user-profile/user-profile.tsx b/frontend/app/src/screens/user-profile/user-profile.tsx
index 833354bb75..99b2367b9e 100644
--- a/frontend/app/src/screens/user-profile/user-profile.tsx
+++ b/frontend/app/src/screens/user-profile/user-profile.tsx
@@ -1,21 +1,20 @@
import { Avatar } from "@/components/display/avatar";
import { Tabs } from "@/components/tabs";
-import { ACCOUNT_OBJECT } from "@/config/constants";
+import { ACCOUNT_GENERIC_OBJECT } from "@/config/constants";
import { QSP } from "@/config/qsp";
import { getProfileDetails } from "@/graphql/queries/accounts/getProfileDetails";
-import useQuery from "@/hooks/useQuery";
import { useTitle } from "@/hooks/useTitle";
import ErrorScreen from "@/screens/errors/error-screen";
import Content from "@/screens/layout/content";
import LoadingScreen from "@/screens/loading-screen/loading-screen";
import { genericsState } from "@/state/atoms/schema.atom";
-import { gql } from "@apollo/client";
+import { gql, useQuery } from "@apollo/client";
import { useAtomValue } from "jotai";
import { StringParam, useQueryParam } from "use-query-params";
+import NoDataFound from "../errors/no-data-found";
import TabPreferences from "./tab-preferences";
import TabProfile from "./tab-profile";
import TabTokens from "./tab-tokens";
-import NoDataFound from "../errors/no-data-found";
const PROFILE_TABS = {
PROFILE: "profile",
@@ -54,7 +53,7 @@ export function UserProfilePage() {
const schemaList = useAtomValue(genericsState);
useTitle("Profile");
- const schema = schemaList.find((s) => s.kind === ACCOUNT_OBJECT);
+ const schema = schemaList.find((s) => s.kind === ACCOUNT_GENERIC_OBJECT);
const queryString = schema
? getProfileDetails({
diff --git a/frontend/app/src/state/atoms/config.atom.ts b/frontend/app/src/state/atoms/config.atom.ts
index 410ff24ad3..0e39e7c5a3 100644
--- a/frontend/app/src/state/atoms/config.atom.ts
+++ b/frontend/app/src/state/atoms/config.atom.ts
@@ -21,11 +21,24 @@ export type MainConfig = {
allow_anonymous_access: boolean;
};
+export type Provider = {
+ name: string;
+ display_label: string;
+ icon: string;
+ protocol: string;
+ readonly authorize_path: string;
+ readonly token_path: string;
+};
+
export type Config = {
analytics: AnalyticsConfig;
logging: LoggingConfig;
main: MainConfig;
experimental_features: { [key: string]: boolean };
+ sso: {
+ enabled: boolean;
+ providers: Array;
+ };
};
export const configState = atom(undefined);
diff --git a/frontend/app/src/styles/index.css b/frontend/app/src/styles/index.css
index e3be6decc0..cf42da013d 100644
--- a/frontend/app/src/styles/index.css
+++ b/frontend/app/src/styles/index.css
@@ -9,7 +9,7 @@ body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
"Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
- font-family: "Montserrat", sans-serif;
+ font-family: "Inter", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
diff --git a/frontend/app/src/utils/common.ts b/frontend/app/src/utils/common.ts
index 21531132ba..ddfef14451 100644
--- a/frontend/app/src/utils/common.ts
+++ b/frontend/app/src/utils/common.ts
@@ -1,5 +1,5 @@
-import { iGenericSchema, IModelSchema } from "@/state/atoms/schema.atom";
-import { clsx, type ClassValue } from "clsx";
+import { IModelSchema, iGenericSchema } from "@/state/atoms/schema.atom";
+import { type ClassValue, clsx } from "clsx";
import * as R from "ramda";
import { twMerge } from "tailwind-merge";
diff --git a/frontend/app/src/utils/getSchemaObjectColumns.ts b/frontend/app/src/utils/getSchemaObjectColumns.ts
index f2a88dc206..ccecc9257e 100644
--- a/frontend/app/src/utils/getSchemaObjectColumns.ts
+++ b/frontend/app/src/utils/getSchemaObjectColumns.ts
@@ -1,3 +1,4 @@
+import { SelectOption } from "@/components/inputs/select";
import {
attributesKindForDetailsViewExclude,
attributesKindForListView,
@@ -9,7 +10,6 @@ import { store } from "@/state";
import { iGenericSchema, iNodeSchema, profilesAtom } from "@/state/atoms/schema.atom";
import * as R from "ramda";
import { isGeneric, sortByOrderWeight } from "./common";
-import { SelectOption } from "@/components/inputs/select";
type tgetObjectAttributes = {
schema: iNodeSchema | iGenericSchema | undefined;
diff --git a/frontend/app/src/utils/objects.ts b/frontend/app/src/utils/objects.ts
index 54ad0aacb6..a36cfe53bf 100644
--- a/frontend/app/src/utils/objects.ts
+++ b/frontend/app/src/utils/objects.ts
@@ -1,14 +1,15 @@
import { constructPathForIpam } from "@/screens/ipam/common/utils";
import {
- IP_ADDRESS_GENERIC,
- IP_PREFIX_GENERIC,
IPAM_QSP,
IPAM_ROUTE,
+ IP_ADDRESS_GENERIC,
+ IP_PREFIX_GENERIC,
} from "@/screens/ipam/constants";
+import { RESOURCE_GENERIC_KIND } from "@/screens/resource-manager/constants";
import { store } from "@/state";
-import { profilesAtom, schemaState } from "@/state/atoms/schema.atom";
+import { genericsState, profilesAtom, schemaState } from "@/state/atoms/schema.atom";
+import { isGeneric } from "@/utils/common";
import { constructPath, overrideQueryParams } from "./fetch";
-import { RESOURCE_GENERIC_KIND } from "@/screens/resource-manager/constants";
const regex = /^Related/; // starts with Related
@@ -23,26 +24,40 @@ export const getObjectDetailsUrl2 = (
objectId?: string,
overrideParams?: overrideQueryParams[]
) => {
- const nodes = store.get(schemaState);
- const profiles = store.get(profilesAtom);
- const schema = [...nodes, ...profiles].find(({ kind }) => kind === objectKind);
- if (!schema) return constructPath("/", overrideParams);
-
- const inheritFrom = schema.inherit_from;
-
- if (inheritFrom?.includes(IP_PREFIX_GENERIC)) {
+ if (objectKind === IP_PREFIX_GENERIC) {
return constructPathForIpam(`${IPAM_ROUTE.PREFIXES}/${objectId}`, overrideParams);
}
- if (inheritFrom?.includes(IP_ADDRESS_GENERIC)) {
+ if (objectKind === IP_ADDRESS_GENERIC) {
return constructPathForIpam(`${IPAM_ROUTE.ADDRESSES}/${objectId}`, [
{ name: IPAM_QSP.TAB, value: "ip-details" },
...(overrideParams ?? []),
]);
}
- if (inheritFrom?.includes(RESOURCE_GENERIC_KIND)) {
- return constructPathForIpam(`/resource-manager/${objectId}`, overrideParams);
+ const nodes = store.get(schemaState);
+ const generics = store.get(genericsState);
+ const profiles = store.get(profilesAtom);
+ const schema = [...nodes, ...generics, ...profiles].find(({ kind }) => kind === objectKind);
+ if (!schema) return "#";
+
+ if (!isGeneric(schema)) {
+ const inheritFrom = schema.inherit_from;
+
+ if (inheritFrom?.includes(IP_PREFIX_GENERIC)) {
+ return constructPathForIpam(`${IPAM_ROUTE.PREFIXES}/${objectId}`, overrideParams);
+ }
+
+ if (inheritFrom?.includes(IP_ADDRESS_GENERIC)) {
+ return constructPathForIpam(`${IPAM_ROUTE.ADDRESSES}/${objectId}`, [
+ { name: IPAM_QSP.TAB, value: "ip-details" },
+ ...(overrideParams ?? []),
+ ]);
+ }
+
+ if (inheritFrom?.includes(RESOURCE_GENERIC_KIND)) {
+ return constructPathForIpam(`/resource-manager/${objectId}`, overrideParams);
+ }
}
const path = objectId ? `/objects/${objectKind}/${objectId}` : `/objects/${objectKind}`;
diff --git a/frontend/app/tests/e2e/auth.setup.ts b/frontend/app/tests/e2e/auth.setup.ts
index a12dc9746c..206ae7fd0f 100644
--- a/frontend/app/tests/e2e/auth.setup.ts
+++ b/frontend/app/tests/e2e/auth.setup.ts
@@ -13,7 +13,7 @@ setup("authenticate admin", async ({ page }) => {
await page.getByLabel("Password").fill(ADMIN_CREDENTIALS.password);
await page.getByRole("button", { name: "Sign in" }).click();
- await expect(page.getByTestId("current-user-avatar-button")).toBeVisible();
+ await expect(page.getByTestId("authenticated-menu-trigger")).toBeVisible();
await page.context().storageState({ path: ACCOUNT_STATE_PATH.ADMIN });
});
@@ -24,7 +24,7 @@ setup("authenticate read-write", async ({ page }) => {
await page.getByLabel("Password").fill(READ_WRITE_CREDENTIALS.password);
await page.getByRole("button", { name: "Sign in" }).click();
- await expect(page.getByTestId("current-user-avatar-button")).toBeVisible();
+ await expect(page.getByTestId("authenticated-menu-trigger")).toBeVisible();
await page.context().storageState({ path: ACCOUNT_STATE_PATH.READ_WRITE });
});
@@ -35,6 +35,6 @@ setup("authenticate read-only", async ({ page }) => {
await page.getByLabel("Password").fill(READ_ONLY_CREDENTIALS.password);
await page.getByRole("button", { name: "Sign in" }).click();
- await expect(page.getByTestId("current-user-avatar-button")).toBeVisible();
+ await expect(page.getByTestId("authenticated-menu-trigger")).toBeVisible();
await page.context().storageState({ path: ACCOUNT_STATE_PATH.READ_ONLY });
});
diff --git a/frontend/app/tests/e2e/branches.spec.ts b/frontend/app/tests/e2e/branches.spec.ts
index 0ea38cc253..bb8ca2f003 100644
--- a/frontend/app/tests/e2e/branches.spec.ts
+++ b/frontend/app/tests/e2e/branches.spec.ts
@@ -14,7 +14,7 @@ test.describe("Branches creation and deletion", () => {
test.describe("when not logged in", () => {
test("should not be able to create a branch if not logged in", async ({ page }) => {
await page.goto("/");
- await expect(page.getByTestId("branch-select-menu")).toContainText("main");
+ await page.getByTestId("branch-selector-trigger").click();
await expect(page.getByTestId("create-branch-button")).toBeDisabled();
});
});
@@ -25,6 +25,7 @@ test.describe("Branches creation and deletion", () => {
test("should create a new branch", async ({ page }) => {
await page.goto("/");
+ await page.getByTestId("branch-selector-trigger").click();
await page.getByTestId("create-branch-button").click();
// Form
@@ -34,16 +35,16 @@ test.describe("Branches creation and deletion", () => {
await page.getByRole("button", { name: "Create a new branch" }).click();
// After submit
- await expect(page.getByTestId("branch-select-menu")).toContainText("test123");
+ await expect(page.getByTestId("branch-selector-trigger")).toContainText("test123");
await expect(page).toHaveURL(/.*?branch=test123/);
});
test("should display the new branch", async ({ page }) => {
await page.goto("/");
- await page.getByTestId("branch-list-display-button").click();
- await expect(page.getByTestId("branch-list-dropdown")).toContainText("test123");
+ await page.getByTestId("branch-selector-trigger").click();
+ await expect(page.getByTestId("branch-list")).toContainText("test123");
- await page.getByTestId("sidebar-menu").getByText("Branches").click();
+ await page.getByRole("link", { name: "View all branches" }).click();
await expect(page).toHaveURL(/.*\/branches/);
await page.getByTestId("branches-items").getByText("test123").click();
@@ -71,23 +72,22 @@ test.describe("Branches creation and deletion", () => {
await modalDelete.getByRole("button", { name: "Delete" }).click();
// we should stay on the branch test123
- await expect(page.getByTestId("branch-select-menu")).toContainText("test123");
- await page.getByTestId("branch-list-display-button").click();
- await expect(page.getByTestId("branch-list-dropdown")).toContainText("test123");
- await expect(page.getByTestId("branch-list-dropdown")).not.toContainText("test456");
+ await expect(page.getByTestId("branch-selector-trigger")).toContainText("test123");
+ await page.getByTestId("branch-selector-trigger").click();
+ await expect(page.getByTestId("branch-list")).toContainText("test123");
+ await expect(page.getByTestId("branch-list")).not.toContainText("test456");
expect(page.url()).toContain("/branches?branch=test123");
});
test("should delete the currently selected branch", async ({ page }) => {
- await page.goto("/");
- await page.getByRole("link", { name: "Branches" }).click();
+ await page.goto("/branches");
await page.getByText("test123").click();
await page.getByRole("button", { name: "Delete" }).click();
await page.getByTestId("modal-delete-confirm").click();
expect(page.url()).toContain("/branches");
- await page.getByTestId("branch-list-display-button").click();
- await expect(page.getByTestId("branch-list-dropdown")).not.toContainText("test123");
+ await page.getByTestId("branch-selector-trigger").click();
+ await expect(page.getByTestId("branch-list")).not.toContainText("test123");
});
});
});
diff --git a/frontend/app/tests/e2e/ipam/ip-address-list.spec.ts b/frontend/app/tests/e2e/ipam/ip-address-list.spec.ts
index 32edbf10db..ec15762e49 100644
--- a/frontend/app/tests/e2e/ipam/ip-address-list.spec.ts
+++ b/frontend/app/tests/e2e/ipam/ip-address-list.spec.ts
@@ -31,13 +31,13 @@ test.describe("/ipam/addresses - IP Address list", () => {
await page.goto("/ipam/addresses?ipam-tab=ip-details");
await test.step("select a prefix to view all ip addresses", async () => {
- await page.getByRole("treeitem", { name: "172.20.20.0/27" }).click();
- await expect(page.getByText("172.20.20.0/27IP Addresses")).toBeVisible();
+ await page.getByRole("treeitem", { name: "172.16.0.0/16" }).click();
+ await expect(page.getByText("172.16.0.0/16IP Addresses")).toBeVisible();
await expect(page.getByText("Showing 1 to ")).toBeVisible();
});
await test.step("click on any ip address row to view summary", async () => {
- await page.getByRole("link", { name: "172.20.20.1/28" }).click();
+ await page.getByRole("link", { name: "172.16.0.1/16" }).click();
await expect(page.getByText("Ipam IP Address summary")).toBeVisible();
await expect(page.url()).toContain("ipam-tab=ip-details");
});
@@ -45,7 +45,7 @@ test.describe("/ipam/addresses - IP Address list", () => {
await test.step("use breadcrumb to go back to parent prefix", async () => {
await page.getByRole("link", { name: "All IP Addresses" }).click();
await expect(page.getByText("Showing 1 to ")).toBeVisible();
- await expect(page.locator("[aria-selected=true]")).toContainText("172.20.20.0/27");
+ await expect(page.locator("[aria-selected=true]")).toContainText("172.16.0.0/16");
await expect(page.url()).toContain("/prefixes/");
});
});
diff --git a/frontend/app/tests/e2e/ipam/ipam-crud.spec.ts b/frontend/app/tests/e2e/ipam/ipam-crud.spec.ts
index c6ed72b982..4ba8cb5f16 100644
--- a/frontend/app/tests/e2e/ipam/ipam-crud.spec.ts
+++ b/frontend/app/tests/e2e/ipam/ipam-crud.spec.ts
@@ -22,7 +22,7 @@ test.describe("/ipam - Ipam home page", () => {
test("should load all ipam home page elements", async ({ page }) => {
await page.goto("/ipam");
- await expect(page.getByText("IP Address Manager")).toBeVisible();
+ await expect(page.getByRole("heading", { name: "IP Address Manager" })).toBeVisible();
await expect(page.getByTestId("ipam-tree")).toBeVisible();
await expect(page.getByTestId("ipam-main-content")).toBeVisible();
});
diff --git a/frontend/app/tests/e2e/ipam/prefix-list.spec.ts b/frontend/app/tests/e2e/ipam/prefix-list.spec.ts
index c71207e9b5..ccf1741c9a 100644
--- a/frontend/app/tests/e2e/ipam/prefix-list.spec.ts
+++ b/frontend/app/tests/e2e/ipam/prefix-list.spec.ts
@@ -7,13 +7,13 @@ test.describe("/ipam/prefixes - Prefix list", () => {
await page.getByRole("option", { name: "50" }).click();
await page
.getByTestId("ipam-main-content")
- .getByRole("row", { name: "203.0.113.0/24 - prefix" }) // prefix need pagination to be visible
- .getByRole("link", { name: "203.0.113.0/24" }) // prefix need pagination to be visible
+ .getByRole("row", { name: "203.111.0.0/16 - prefix" }) // prefix need pagination to be visible
+ .getByRole("link", { name: "203.111.0.0/16" }) // prefix need pagination to be visible
.click();
- expect(page.url()).toContain("/ipam/prefixes/");
await expect(page.getByText("Ipam IP Prefix summary")).toBeVisible();
- await expect(page.getByText("Prefix203.0.113.0/24")).toBeVisible();
- await expect(page.getByText("Utilization93%")).toBeVisible();
+ expect(page.url()).toContain("/ipam/prefixes/");
+ await expect(page.getByText("Prefix203.111.0.0/16")).toBeVisible();
+ await expect(page.getByText("Utilization0%")).toBeVisible();
await expect(page.getByRole("progressbar")).toBeVisible();
await expect(page.getByText("Ip Namespacedefault")).toBeVisible();
});
@@ -25,13 +25,13 @@ test.describe("/ipam/prefixes - Prefix list", () => {
);
await test.step("select a prefix to view all sub prefixes", async () => {
- await page.getByRole("treeitem", { name: "2001:db8::/112" }).click();
- await expect(page.getByTestId("ipam-main-content")).toContainText("2001:db8::/112");
+ await page.getByRole("treeitem", { name: "2001:db8::/100" }).click();
+ await expect(page.getByTestId("ipam-main-content")).toContainText("2001:db8::/100");
await expect(page.getByTestId("ipam-main-content")).toContainText("Showing 1 to ");
});
- await test.step("to to any sub prefix list of any children prefix", async () => {
- await page.getByRole("link", { name: "2001:db8::/120" }).click();
+ await test.step("go to any sub prefix list of any children prefix", async () => {
+ await page.getByRole("link", { name: "2001:db8::/110" }).click();
await expect(page.getByTestId("ipam-main-content")).toContainText("Showing 0 of 0 results");
await expect(page.url()).toContain("ipam-tab=prefix-details");
});
@@ -39,7 +39,7 @@ test.describe("/ipam/prefixes - Prefix list", () => {
await test.step("use breadcrumb to go back to parent prefix", async () => {
await page
.getByTestId("ipam-main-content")
- .getByRole("link", { name: "2001:db8::/112" })
+ .getByRole("link", { name: "2001:db8::/100" })
.click();
await expect(page.getByTestId("ipam-main-content")).toContainText("Showing 1 to ");
await expect(page.url()).toContain("ipam-tab=prefix-details");
diff --git a/frontend/app/tests/e2e/ipam/prefix-summary.spec.ts b/frontend/app/tests/e2e/ipam/prefix-summary.spec.ts
index 2088db9069..49b054b0f2 100644
--- a/frontend/app/tests/e2e/ipam/prefix-summary.spec.ts
+++ b/frontend/app/tests/e2e/ipam/prefix-summary.spec.ts
@@ -4,8 +4,8 @@ test.describe("/ipam/prefixes/:prefixId - Prefix summary", () => {
test("go to prefix summary when clicking on any tree item", async ({ page }) => {
await page.goto("/ipam");
await page.getByTestId("ipam-tree").getByRole("link", { name: "10.0.0.0/8" }).click();
- expect(page.url()).toContain("/ipam/prefixes/");
await expect(page.getByText("Ipam IP Prefix summary")).toBeVisible();
+ expect(page.url()).toContain("/ipam/prefixes/");
await expect(page.getByText("Prefix10.0.0.0/8")).toBeVisible();
await expect(page.getByText("Utilization1%")).toBeVisible();
await expect(page.getByRole("progressbar")).toBeVisible();
@@ -13,6 +13,7 @@ test.describe("/ipam/prefixes/:prefixId - Prefix summary", () => {
await test.step("go to all prefixes with breadcrumb", async () => {
await page.getByRole("link", { name: "All Prefixes" }).click();
+ await expect(page.getByRole("columnheader", { name: "Prefix" })).toBeVisible();
expect(page.url()).toContain("/ipam/prefixes");
});
});
diff --git a/frontend/app/tests/e2e/menu.spec.ts b/frontend/app/tests/e2e/menu.spec.ts
deleted file mode 100644
index 25515c812a..0000000000
--- a/frontend/app/tests/e2e/menu.spec.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { expect, test } from "@playwright/test";
-
-test.describe("Sidebar menu", () => {
- test.beforeEach(async function ({ page }) {
- page.on("response", async (response) => {
- if (response.status() === 500) {
- await expect(response.url()).toBe("This URL responded with a 500 status");
- }
- });
- });
-
- test("filter item in menu", async ({ page }) => {
- await page.goto("/");
-
- await test.step("all items are visible", async () => {
- await expect(page.getByRole("button", { name: "BGP Session" })).toBeVisible();
- await expect(page.getByRole("link", { name: "All BGP Session(s)" })).toBeVisible();
- await expect(page.getByRole("link", { name: "BGP Peer Group" })).toBeVisible();
- await expect(page.getByRole("link", { name: "Circuit" })).toBeVisible();
- });
-
- await test.step("filter with text 'inter'", async () => {
- await page.getByTestId("search-menu").fill("inter");
- });
-
- await test.step("only items who includes 'inter' are visible", async () => {
- await expect(page.getByRole("button", { name: "Device" })).toBeVisible();
- await expect(page.getByRole("link", { name: "Interface", exact: true })).toBeVisible();
- await expect(page.getByRole("link", { name: "MLAG Interface", exact: true })).toBeVisible();
- });
- });
-
- test("display groups and all items when group matches but no items matches", async ({ page }) => {
- await page.goto("/");
-
- await page.getByTestId("search-menu").fill("ipam");
-
- await test.step("all items under Ipam group are visible", async () => {
- await expect(page.getByRole("button", { name: "IPAM" })).toBeVisible();
- await expect(page.getByRole("link", { name: "Namespaces" })).toBeVisible();
- await expect(page.getByRole("link", { name: "Prefixes" })).toBeVisible();
- await expect(page.getByRole("link", { name: "IP Addresses" })).toBeVisible();
- });
- });
-
- test("display no items nor groups when there is no match", async ({ page }) => {
- await page.goto("/");
- await expect(page.getByRole("button", { name: "Objects" })).toBeVisible();
-
- await page.getByTestId("search-menu").fill("no-item-found");
-
- await expect(page.getByTestId("sidebar-menu").getByRole("link")).toBeHidden();
- });
-});
diff --git a/frontend/app/tests/e2e/objects/artifact-definition.spec.ts b/frontend/app/tests/e2e/objects/artifact-definition.spec.ts
index 51d64199e7..76dea04e7d 100644
--- a/frontend/app/tests/e2e/objects/artifact-definition.spec.ts
+++ b/frontend/app/tests/e2e/objects/artifact-definition.spec.ts
@@ -13,8 +13,8 @@ test.describe("/objects/CoreArtifactDefinition - Artifact Definition page", () =
});
test("should generate artifacts successfully", async ({ page }) => {
- await page.goto("/objects/CoreArtifactDefinition"),
- await page.getByRole("link", { name: "startup-config" }).click();
+ await page.goto("/objects/CoreArtifactDefinition");
+ await page.getByRole("link", { name: "startup-config" }).click();
await page.getByRole("button", { name: "Generate" }).click();
await expect(page.getByRole("alert")).toContainText("Artifacts generated");
});
diff --git a/frontend/app/tests/e2e/objects/object-details.spec.ts b/frontend/app/tests/e2e/objects/object-details.spec.ts
index 1ab185e5d7..fbd08decb4 100644
--- a/frontend/app/tests/e2e/objects/object-details.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-details.spec.ts
@@ -60,9 +60,7 @@ test.describe("/objects/:objectKind/:objectid", () => {
});
test("should display the select 2 steps correctly", async ({ page }) => {
- await page.goto("/");
- await page.getByRole("link", { name: "All Device(s)" }).click();
- await expect(page.getByText("Just a moment")).not.toBeVisible();
+ await page.goto("/objects/InfraDevice");
await page.getByRole("link", { name: "atl1-edge1" }).click();
await page.getByText("Interfaces15").click();
await page.getByRole("link", { name: "Backbone: Connected to jfk1-" }).click();
diff --git a/frontend/app/tests/e2e/objects/object-dropdown-creation.spec.ts b/frontend/app/tests/e2e/objects/object-dropdown-creation.spec.ts
index b3e8f93057..caa94d9f89 100644
--- a/frontend/app/tests/e2e/objects/object-dropdown-creation.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-dropdown-creation.spec.ts
@@ -13,20 +13,7 @@ test.describe("object dropdown creation", () => {
});
test("should open the creation form and open the tag option creation form", async ({ page }) => {
- // Go to home page
- await page.goto("/");
-
- await Promise.all([
- page.waitForResponse((response) => {
- const reqData = response.request().postDataJSON();
- const status = response.status();
-
- return reqData?.operationName === "InfraDevice" && status === 200;
- }),
-
- // Open all devices
- page.getByRole("link", { name: "All Device(s)" }).click(),
- ]);
+ await page.goto("/objects/InfraDevice");
// Open creation form
await page.getByTestId("create-object-button").click();
diff --git a/frontend/app/tests/e2e/objects/object-filters.spec.ts b/frontend/app/tests/e2e/objects/object-filters.spec.ts
index 83bb96104c..fddc0669c5 100644
--- a/frontend/app/tests/e2e/objects/object-filters.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-filters.spec.ts
@@ -12,20 +12,15 @@ test.describe("Object filters", () => {
test("should filter the objects list", async ({ page }) => {
await test.step("access objects list and verify initial state", async () => {
await page.goto("/objects/InfraDevice");
- await expect(page.getByRole("main")).toContainText("Filters: 0");
- await expect(page.getByRole("main")).toContainText("Showing 1 to 10 of 30 results");
+ await expect(page.getByTestId("object-items")).toContainText("Filters: 0");
+ await expect(page.getByTestId("object-items")).toContainText("Showing 1 to 10 of 30 results");
});
await test.step("start filtering objects", async () => {
await test.step("select filters", async () => {
await page.getByTestId("apply-filters").click();
- await page
- .getByTestId("side-panel-container")
- .getByText("Status")
- .locator("../..")
- .getByTestId("select-open-option-button")
- .click();
- await page.getByRole("option", { name: "Provisioning In the process" }).click();
+ await page.getByLabel("Role").click();
+ await page.getByRole("option", { name: "Edge Router" }).click();
const tagsMultiSelectOpenButton = page
.getByTestId("side-panel-container")
@@ -46,13 +41,7 @@ test.describe("Object filters", () => {
await test.step("verify filter initial value", async () => {
await page.getByTestId("apply-filters").click();
- await expect(
- page
- .getByTestId("side-panel-container")
- .getByText("Status")
- .locator("../..")
- .getByTestId("select-input")
- ).toHaveValue("Provisioning");
+ await expect(page.getByLabel("Role")).toHaveText("Edge Router");
});
await expect(page.locator("form")).toContainText("red");
@@ -62,14 +51,14 @@ test.describe("Object filters", () => {
});
await test.step("verify new state", async () => {
- await expect(page.getByRole("main")).toContainText("Filters: 2");
- await expect(page.getByRole("main")).toContainText("Showing 1 to 6 of 6 results");
+ await expect(page.getByTestId("object-items")).toContainText("Filters: 2");
+ await expect(page.getByTestId("object-items")).toContainText("Showing 1 to 10 of 10 results");
});
await test.step("remove filters and verify initial state", async () => {
await page.getByTestId("remove-filters").click();
- await expect(page.getByRole("main")).toContainText("Filters: 0");
- await expect(page.getByRole("main")).toContainText("Showing 1 to 10 of 30 results");
+ await expect(page.getByTestId("object-items")).toContainText("Filters: 0");
+ await expect(page.getByTestId("object-items")).toContainText("Showing 1 to 10 of 30 results");
});
});
@@ -99,12 +88,7 @@ test.describe("Object filters", () => {
await page.getByTestId("apply-filters").click();
await expect(page.getByTestId("side-panel-container").getByText("Object")).toBeVisible();
- const kindSelector = page
- .getByTestId("side-panel-container")
- .getByText("Kind")
- .locator("../..")
- .getByTestId("select-open-option-button");
- await kindSelector.click();
+ await page.getByLabel("kind").click();
await expect(page.getByRole("option", { name: "Tag Builtin", exact: true })).toBeVisible();
});
@@ -116,22 +100,18 @@ test.describe("Object filters", () => {
await expect(page.getByText("Select an object type")).not.toBeVisible();
});
- const kindSelector = page
- .getByTestId("side-panel-container")
- .getByText("Kind")
- .locator("../..");
-
await test.step("filter objects", async () => {
- await kindSelector.getByTestId("select-open-option-button").click();
+ await page.getByLabel("kind").click();
await page.getByRole("option", { name: "Interface L2 Infra", exact: true }).click();
await page.getByRole("button", { name: "Apply filters" }).click();
- await expect(page.getByRole("main")).toContainText("Showing 1 to 10 of 510 results");
+ await expect(page.getByTestId("object-items")).toContainText(
+ "Showing 1 to 10 of 510 results"
+ );
});
await test.step("verify filter initial value", async () => {
await page.getByTestId("apply-filters").click();
- await kindSelector.getByTestId("select-input");
- await expect(kindSelector.getByTestId("select-input")).toHaveValue("Interface L2");
+ await expect(page.getByLabel("Kind")).toContainText("Interface L2 Infra");
});
});
});
diff --git a/frontend/app/tests/e2e/objects/object-list-search.spec.ts b/frontend/app/tests/e2e/objects/object-list-search.spec.ts
index 4b1c767e19..aa01215b39 100644
--- a/frontend/app/tests/e2e/objects/object-list-search.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-list-search.spec.ts
@@ -17,13 +17,13 @@ test.describe("Object list search", async () => {
await test.step("should access object list and verify the total amount of results", async () => {
await expect(page.locator("tbody")).toContainText(OBJECT_NAME);
- await expect(page.getByRole("main")).toContainText("Showing 1 to 10 of 30 results");
+ await expect(page.getByTestId("object-items")).toContainText("Showing 1 to 10 of 30 results");
});
await test.step("should search an object and verify the total amount of results", async () => {
await page.getByTestId("object-list-search-bar").fill(SEARCH);
await expect(page.locator("tbody")).toContainText(OBJECT_NAME);
- await expect(page.getByRole("main")).toContainText("Showing 1 to 6 of 6 results");
+ await expect(page.getByTestId("object-items")).toContainText("Showing 1 to 6 of 6 results");
});
});
});
diff --git a/frontend/app/tests/e2e/objects/object-list.spec.ts b/frontend/app/tests/e2e/objects/object-list.spec.ts
index cab72ee9ca..104b247046 100644
--- a/frontend/app/tests/e2e/objects/object-list.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-list.spec.ts
@@ -55,7 +55,7 @@ test.describe("/objects/:objectKind", () => {
// then
const newTab = await newTabPromise;
- await newTab.waitForURL(linkHref);
+ await newTab.waitForURL(linkHref!);
expect(newTab.url()).toContain(linkHref);
});
});
diff --git a/frontend/app/tests/e2e/objects/object-metadata.spec.ts b/frontend/app/tests/e2e/objects/object-metadata.spec.ts
index f127256dbc..fb30acb35d 100644
--- a/frontend/app/tests/e2e/objects/object-metadata.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-metadata.spec.ts
@@ -13,10 +13,7 @@ test.describe("Object metadata", () => {
});
test("should contain initial values and update them", async ({ page }) => {
- await page.goto("/");
-
- // Access all devices
- await page.getByRole("link", { name: "All Device(s)" }).click();
+ await page.goto("/objects/InfraDevice");
// Access device details
await page.getByRole("link", { name: "atl1-core2" }).click();
@@ -51,11 +48,8 @@ test.describe("Object metadata", () => {
// Verify the alert
await expect(page.getByText("Metadata updated")).toBeVisible();
- // Verify metadata updates
- await page.goto("/");
-
// Access all devices
- await page.getByRole("link", { name: "All Device(s)" }).click();
+ await page.goto("/objects/InfraDevice");
// Access device details
await page.getByRole("link", { name: "atl1-core2" }).click();
diff --git a/frontend/app/tests/e2e/objects/object-relationships.spec.ts b/frontend/app/tests/e2e/objects/object-relationships.spec.ts
index 8e496431f0..e5889f6e18 100644
--- a/frontend/app/tests/e2e/objects/object-relationships.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-relationships.spec.ts
@@ -26,7 +26,7 @@ test.describe("/objects/:objectKind/:objectid - relationship tab", () => {
await expect(page.getByTestId("manage-groups")).toBeDisabled();
await expect(page.getByTestId("delete-button")).toBeDisabled();
- await page.getByText("Devices5").click();
+ await page.getByText("Devices10").click();
await expect(page.getByTestId("open-relationship-form-button")).toBeDisabled();
});
});
@@ -40,24 +40,24 @@ test.describe("/objects/:objectKind/:objectid - relationship tab", () => {
await test.step("Navigate to relationship tab of an object", async () => {
await page.goto("/objects/InfraPlatform");
await page.getByRole("link", { name: "Cisco IOS", exact: true }).click();
- await page.getByText("Devices5").click();
+ await page.getByText("Devices10").click();
});
await test.step("Delete the relationship", async () => {
await page
- .getByRole("row", { name: "ord1-edge2" })
+ .getByRole("row", { name: "ord1-leaf2" })
.getByTestId("relationship-delete-button")
.click();
await expect(page.getByRole("paragraph")).toContainText(
- "Are you sure you want to remove the association between `Cisco IOS` and `ord1-edge2`? The `InfraDevice` `ord1-edge2` won't be deleted in the process."
+ "Are you sure you want to remove the association between `Cisco IOS` and `ord1-leaf2`? The `InfraDevice` `ord1-leaf2` won't be deleted in the process."
);
await page.getByTestId("modal-delete-confirm").click();
});
await test.step("Verify deletion of relationship", async () => {
await expect(page.getByRole("alert")).toContainText("Item removed from the group");
- await expect(page.getByRole("main")).toContainText("Showing 1 to 4 of 4 results");
- await expect(page.getByLabel("Tabs")).toContainText("Devices4");
+ await expect(page.getByText("Showing 1 to 9 of 9 results")).toBeVisible();
+ await expect(page.getByLabel("Tabs")).toContainText("Devices9");
});
});
@@ -65,21 +65,21 @@ test.describe("/objects/:objectKind/:objectid - relationship tab", () => {
await test.step("Navigate to relationship tab of an object", async () => {
await page.goto("/objects/InfraPlatform");
await page.getByRole("link", { name: "Cisco IOS", exact: true }).click();
- await page.getByText("Devices4").click();
+ await page.getByText("Devices9").click();
});
await test.step("Add a new relationship", async () => {
await page.getByTestId("open-relationship-form-button").click();
await page.getByTestId("side-panel-container").getByLabel("Devices").click();
- await page.getByRole("option", { name: "ord1-edge2" }).click();
+ await page.getByRole("option", { name: "ord1-leaf2" }).click();
await page.getByRole("button", { name: "Save" }).click();
});
await test.step("Verify new relationship addition", async () => {
await expect(page.getByRole("alert")).toContainText("Association with InfraDevice added");
- await expect(page.getByRole("main")).toContainText("Showing 1 to 5 of 5 results");
- await expect(page.getByLabel("Tabs")).toContainText("Devices5");
- await expect(page.getByRole("cell", { name: "ord1-edge2" })).toBeVisible();
+ await expect(page.getByText("Showing 1 to 10 of 10 results")).toBeVisible();
+ await expect(page.getByLabel("Tabs")).toContainText("Devices10");
+ await expect(page.getByRole("cell", { name: "ord1-leaf2" })).toBeVisible();
});
});
@@ -106,7 +106,7 @@ test.describe("/objects/:objectKind/:objectid - relationship tab", () => {
test("should access to the pool selector on relationships add", async ({ page }) => {
await page.goto("/objects/InfraInterfaceL3/");
- await page.getByRole("link", { name: "Connected to den1-edge1" }).click();
+ await page.getByRole("link", { name: "Connected to den1-edge1::Ethernet1" }).click();
await page.getByText("Ip Addresses1").click();
await page.getByTestId("open-relationship-form-button").click();
await expect(page.getByTestId("select-open-pool-option-button")).toBeVisible();
@@ -122,7 +122,7 @@ test.describe("/objects/:objectKind/:objectid - relationship tab", () => {
await test.step("Navigate to relationship tab of an object", async () => {
await page.goto("/objects/InfraPlatform");
await page.getByRole("link", { name: "Cisco IOS", exact: true }).click();
- await page.getByText("Devices5").click();
+ await page.getByText("Devices10").click();
});
await page.getByRole("link", { name: "atl1", exact: true }).first().click();
await expect(page.getByText("Nameatl1")).toBeVisible();
diff --git a/frontend/app/tests/e2e/objects/object-update.spec.ts b/frontend/app/tests/e2e/objects/object-update.spec.ts
index 4373da528c..78ba318c73 100644
--- a/frontend/app/tests/e2e/objects/object-update.spec.ts
+++ b/frontend/app/tests/e2e/objects/object-update.spec.ts
@@ -27,7 +27,7 @@ test.describe("Object update", () => {
await page.getByLabel("Description").fill("New description");
await page.getByTestId("side-panel-container").getByLabel("Status").click();
- await page.getByRole("option", { name: "Active" }).click();
+ await page.getByRole("option", { name: "Maintenance" }).click();
await page.getByTestId("side-panel-container").getByLabel("Role").click();
await page.getByRole("option", { name: "Edge Router" }).click();
@@ -56,7 +56,7 @@ test.describe("Object update", () => {
await expect(page.getByText("Nameatl1-core1-new-name")).toBeVisible();
await expect(page.getByText("New description")).toBeVisible();
await expect(page.getByRole("link", { name: "AS701 701" })).toBeVisible();
- await expect(page.getByText("Active")).toBeVisible();
+ await expect(page.getByText("Maintenance")).toBeVisible();
await expect(page.getByText("Edge Router")).toBeVisible();
await expect(page.getByRole("link", { name: "green" })).toBeVisible();
await expect(page.getByRole("link", { name: "red", exact: true })).toBeVisible();
@@ -67,20 +67,8 @@ test.describe("Object update", () => {
await expect(page.getByLabel("Name *")).toHaveValue("atl1-core1-new-name");
await expect(page.getByLabel("Description")).toHaveValue("New description");
await expect(page.getByLabel("Type *")).toHaveValue("MX204");
- await expect(
- page
- .getByTestId("side-panel-container")
- .getByLabel("Status")
- .locator("../..")
- .locator("input")
- ).toHaveValue("Active");
- await expect(
- page
- .getByTestId("side-panel-container")
- .getByLabel("Role")
- .locator("../..")
- .locator("input")
- ).toHaveValue("Edge Router");
+ await expect(page.getByLabel("Status")).toHaveText("Maintenance");
+ await expect(page.getByLabel("Role")).toHaveText("Edge Router");
await expect(
page.getByTestId("side-panel-container").getByLabel("Asn").locator("../..").locator("input")
).toHaveValue("AS701 701");
@@ -99,7 +87,7 @@ test.describe("Object update", () => {
await test.step("assert initial object values", async () => {
await expect(page.getByText("Nameatl1-leaf1")).toBeVisible();
- await expect(page.getByText("StatusActive")).toBeVisible();
+ // await expect(page.getByText("StatusActive")).toBeVisible();
await expect(page.getByText("RoleLeaf Switch")).toBeVisible();
await expect(page.getByText("AsnAS64496 64496")).toBeVisible();
});
@@ -108,10 +96,10 @@ test.describe("Object update", () => {
await page.getByTestId("edit-button").click();
await page.getByTestId("side-panel-container").getByLabel("Status").click();
- await page.getByRole("option", { name: "Empty", exact: true }).click();
+ await page.getByRole("option", { name: "Active" }).click();
await page.getByTestId("side-panel-container").getByLabel("Role").click();
- await page.getByRole("option", { name: "Empty", exact: true }).click();
+ await page.getByRole("option", { name: "Leaf Switch" }).click();
await page.getByTestId("side-panel-container").getByLabel("Asn").click();
await page.getByRole("option", { name: "Empty", exact: true }).click();
diff --git a/frontend/app/tests/e2e/objects/profiles/profiles.spec.ts b/frontend/app/tests/e2e/objects/profiles/profiles.spec.ts
index ae29a99534..0471f9ccaf 100644
--- a/frontend/app/tests/e2e/objects/profiles/profiles.spec.ts
+++ b/frontend/app/tests/e2e/objects/profiles/profiles.spec.ts
@@ -203,22 +203,22 @@ test.describe("/objects/CoreProfile - Profile for Interface L2 and fields verifi
});
await test.step("verify Interface L2 optional attributes are all visible", async () => {
- await expect(page.getByText("Profile Name *")).toBeVisible();
- await expect(page.getByText("Description")).toBeVisible();
- await expect(page.getByText("MTU")).toBeVisible();
- await expect(page.getByText("Enabled")).toBeVisible();
- await expect(page.getByText("Status")).toBeVisible();
- await expect(page.getByText("Role")).toBeVisible();
+ await expect(page.getByLabel("Profile Name *")).toBeVisible();
+ await expect(page.getByLabel("Description")).toBeVisible();
+ await expect(page.getByLabel("MTU")).toBeVisible();
+ await expect(page.getByLabel("Enabled")).toBeVisible();
+ await expect(page.getByLabel("Status")).toBeVisible();
+ await expect(page.getByLabel("Role")).toBeVisible();
});
await test.step("verify Interface L2 mandatory attributes and relationships are not visible", async () => {
- await expect(page.getByText("Layer2 Mode *")).not.toBeVisible();
- await expect(page.getByText("Speed *")).not.toBeVisible();
- await expect(page.getByText("Untagged VLAN")).not.toBeVisible();
+ await expect(page.getByLabel("Layer2 Mode *")).not.toBeVisible();
+ await expect(page.getByLabel("Speed *")).not.toBeVisible();
+ await expect(page.getByLabel("Untagged VLAN")).not.toBeVisible();
await expect(
page.getByTestId("side-panel-container").getByText("Tagged VLANs")
).not.toBeVisible();
- await expect(page.getByText("Device *")).not.toBeVisible();
+ await expect(page.getByLabel("Device *")).not.toBeVisible();
});
});
@@ -235,11 +235,7 @@ test.describe("/objects/CoreProfile - Profile for Interface L2 and fields verifi
await page.getByLabel("Profile Priority").fill("2000");
await page.getByLabel("MTU").fill("256");
await page.getByLabel("Enabled").check();
- await page
- .locator("div:below(:text('Status'))")
- .first()
- .getByTestId("select-open-option-button")
- .click();
+ await page.getByLabel("Status").click();
await page.getByText("Provisioning").click();
await page.getByRole("button", { name: "Save" }).click();
await expect(page.getByText("InfraInterfaceL2 created")).toBeVisible();
@@ -257,11 +253,7 @@ test.describe("/objects/CoreProfile - Profile for Interface L2 and fields verifi
await test.step("fill and submit form", async () => {
await page.getByLabel("Profile Name *").fill(GENERIC_PROFILE_NAME);
await page.getByLabel("Profile Priority").fill("2000");
- await page
- .locator("div:below(:text('Status'))")
- .first()
- .getByTestId("select-open-option-button")
- .click();
+ await page.getByLabel("Status").click();
await page.getByText("Maintenance", { exact: true }).click();
await page.getByRole("button", { name: "Save" }).click();
await expect(page.getByText("InfraInterface created")).toBeVisible();
diff --git a/frontend/app/tests/e2e/permissions/accounts-object.spec.ts b/frontend/app/tests/e2e/permissions/accounts-object.spec.ts
index 63bf86db96..de0343bb7a 100644
--- a/frontend/app/tests/e2e/permissions/accounts-object.spec.ts
+++ b/frontend/app/tests/e2e/permissions/accounts-object.spec.ts
@@ -1,4 +1,4 @@
-import { test, expect } from "@playwright/test";
+import { expect, test } from "@playwright/test";
import { ACCOUNT_STATE_PATH } from "../../constants";
test.describe("/objects/CoreGenericAccount - Admin permissions", () => {
diff --git a/frontend/app/tests/e2e/profile/profile.spec.ts b/frontend/app/tests/e2e/profile/profile.spec.ts
index 08ece5ee0d..9b403f3758 100644
--- a/frontend/app/tests/e2e/profile/profile.spec.ts
+++ b/frontend/app/tests/e2e/profile/profile.spec.ts
@@ -14,8 +14,8 @@ test.describe("/profile", () => {
test("should see 'Sign in' and no user avatar on header", async ({ page }) => {
await page.goto("/");
- await expect(page.getByRole("link", { name: "Sign in" })).toBeVisible();
- await expect(page.getByTestId("current-user-avatar-button")).toBeHidden();
+ await expect(page.getByTestId("unauthenticated-menu-trigger")).toBeVisible();
+ await expect(page.getByTestId("authenticated-menu-trigger")).toBeHidden();
});
});
@@ -25,8 +25,8 @@ test.describe("/profile", () => {
test("should access the profile page", async ({ page }) => {
await test.step("go to profile page", async () => {
await page.goto("/");
- await page.getByTestId("current-user-avatar-button").click();
- await page.getByRole("menuitem", { name: "Your Profile" }).click();
+ await page.getByTestId("authenticated-menu-trigger").click();
+ await page.getByRole("menuitem", { name: "Account settings" }).click();
});
await test.step("display account details", async () => {
@@ -44,8 +44,8 @@ test.describe("/profile", () => {
test("should access the profile page", async ({ page }) => {
await test.step("go to profile page", async () => {
await page.goto("/");
- await page.getByTestId("current-user-avatar-button").click();
- await page.getByRole("menuitem", { name: "Your Profile" }).click();
+ await page.getByTestId("authenticated-menu-trigger").click();
+ await page.getByRole("menuitem", { name: "Account settings" }).click();
});
await test.step("display account details", async () => {
@@ -64,8 +64,8 @@ test.describe("/profile", () => {
test("should access the profile page", async ({ page }) => {
await test.step("go to profile page", async () => {
await page.goto("/");
- await page.getByTestId("current-user-avatar-button").click();
- await page.getByRole("menuitem", { name: "Your Profile" }).click();
+ await page.getByTestId("authenticated-menu-trigger").click();
+ await page.getByRole("menuitem", { name: "Account settings" }).click();
});
await test.step("display account details", async () => {
diff --git a/frontend/app/tests/e2e/profile/tokens.spec.ts b/frontend/app/tests/e2e/profile/tokens.spec.ts
index 7f0ba3ddd9..35aa54ea82 100644
--- a/frontend/app/tests/e2e/profile/tokens.spec.ts
+++ b/frontend/app/tests/e2e/profile/tokens.spec.ts
@@ -12,8 +12,6 @@ test.describe("/profile?tab=tokens", () => {
test.describe("when not logged in as admin account", () => {
test("should not access profile tokens", async ({ page }) => {
- await page.goto("/");
- await expect(page.getByText("Just a moment")).not.toBeVisible();
await page.goto("/profile?tab=tokens");
await expect(page.getByText("Welcome to Infrahub")).toBeVisible();
});
@@ -25,12 +23,11 @@ test.describe("/profile?tab=tokens", () => {
test("should access and manage profile tokens", async ({ page }) => {
await test.step("go to profile page and access tokens", async () => {
await page.goto("/");
- await page.getByTestId("current-user-avatar-button").click();
- await page.getByRole("menuitem", { name: "Your Profile" }).click();
+ await page.getByTestId("authenticated-menu-trigger").click();
+ await page.getByRole("menuitem", { name: "Account settings" }).click();
await page.getByText("Tokens").click();
await expect(page.getByRole("heading", { name: "Tokens" })).toBeVisible();
await expect(page.getByTestId("create-object-button")).toBeVisible();
- await expect(page.getByText("Just a moment")).not.toBeVisible();
});
await test.step("create a new token", async () => {
@@ -56,7 +53,7 @@ test.describe("/profile?tab=tokens", () => {
await expect(page.getByText("Are you sure you want to")).toBeVisible();
await page.getByTestId("modal-delete-confirm").click();
await expect(page.getByText("Are you sure you want to")).not.toBeVisible();
- await expect(page.getByText("test token")).not.toBeVisible();
+ await expect(page.getByRole("cell", { name: "test token" })).not.toBeVisible();
});
});
});
diff --git a/frontend/app/tests/e2e/proposed-changes/proposed-changes.spec.ts b/frontend/app/tests/e2e/proposed-changes/proposed-changes.spec.ts
index 625c8dfdf1..3e30be3f1e 100644
--- a/frontend/app/tests/e2e/proposed-changes/proposed-changes.spec.ts
+++ b/frontend/app/tests/e2e/proposed-changes/proposed-changes.spec.ts
@@ -15,7 +15,7 @@ test.describe("/proposed-changes", () => {
test("should not be able to create a proposed changes", async ({ page }) => {
await page.goto("/proposed-changes");
- await expect(page.locator("header").getByText("Proposed changes")).toBeVisible();
+ await expect(page.getByRole("heading", { name: "Proposed changes" })).toBeVisible();
await expect(page.getByTestId("add-proposed-changes-button")).toBeDisabled();
});
});
@@ -26,16 +26,16 @@ test.describe("/proposed-changes", () => {
test("allow to create a proposed change", async ({ page }) => {
await page.goto("/proposed-changes");
- await expect(page.locator("header").getByText("Proposed changes")).toBeVisible();
+ await expect(page.getByRole("heading", { name: "Proposed changes" })).toBeVisible();
await expect(page.getByTestId("add-proposed-changes-button")).toBeEnabled();
await page.getByTestId("add-proposed-changes-button").click();
- await expect(page.getByRole("main")).toContainText("Create a proposed change");
+ await expect(page.getByRole("heading", { name: "Create a proposed change" })).toBeVisible();
});
test("display validation errors when form is submitted with wrong value", async ({ page }) => {
await page.goto("/proposed-changes/new");
- await expect(page.getByRole("main")).toContainText("Create a proposed change");
+ await expect(page.getByRole("heading", { name: "Create a proposed change" })).toBeVisible();
await page.getByRole("button", { name: "Create proposed change" }).click();
await expect(page.getByLabel("Name *").locator("..")).toContainText("Required");
await expect(page.getByText("Source Branch *").locator("..")).toContainText("Required");
@@ -101,7 +101,7 @@ test.describe("/proposed-changes", () => {
await page.getByRole("button", { name: "Save" }).click();
await expect(page.getByText("ProposedChange updated")).toBeVisible();
- await expect(page.locator("header").getByText(pcNameEdit)).toBeVisible();
+ await expect(page.getByRole("heading", { name: pcNameEdit, exact: true })).toBeVisible();
await expect(page.getByTestId("pc-description")).toContainText("My description edit");
await expect(page.getByText("ReviewersAT")).toBeVisible();
});
diff --git a/frontend/app/tests/e2e/proposed-changes/proposed-changes_checks.spec.ts b/frontend/app/tests/e2e/proposed-changes/proposed-changes_checks.spec.ts
index 6514c38032..09443db7df 100644
--- a/frontend/app/tests/e2e/proposed-changes/proposed-changes_checks.spec.ts
+++ b/frontend/app/tests/e2e/proposed-changes/proposed-changes_checks.spec.ts
@@ -18,7 +18,7 @@ test.describe("/proposed-changes checks", () => {
await test.step("create a new proposed change", async () => {
await page.getByTestId("add-proposed-changes-button").click();
- await expect(page.getByText("Create Proposed Change")).toBeVisible();
+ await expect(page.getByRole("heading", { name: "Create a proposed change" })).toBeVisible();
await page.getByLabel("Name *").fill("pc-checks");
await page.getByLabel("Source Branch *").click();
await page.getByRole("option", { name: "atl1-delete-upstream" }).click();
diff --git a/frontend/app/tests/e2e/proposed-changes/proposed-changes_diff.spec.ts b/frontend/app/tests/e2e/proposed-changes/proposed-changes_diff.spec.ts
index ee4a14c6fa..33c6be3b9f 100644
--- a/frontend/app/tests/e2e/proposed-changes/proposed-changes_diff.spec.ts
+++ b/frontend/app/tests/e2e/proposed-changes/proposed-changes_diff.spec.ts
@@ -1,4 +1,4 @@
-import { test, expect } from "@playwright/test";
+import { expect, test } from "@playwright/test";
import { ACCOUNT_STATE_PATH } from "../../constants";
test.describe("/proposed-changes diff data", () => {
@@ -24,7 +24,7 @@ test.describe("/proposed-changes diff data", () => {
await page.getByLabel("Name *").fill("conflict-test");
await page.getByTestId("select-open-option-button").click();
await page.getByRole("option", { name: "Admin" }).click();
- await page.getByRole("main").click();
+ await page.getByTestId("select-open-option-button").click();
await page.getByRole("button", { name: "Create proposed change" }).click();
await expect(page.getByText("Proposed change created")).toBeVisible();
await page.getByText("Data").click();
diff --git a/frontend/app/tests/e2e/resource-manager/number-pool.spec.ts b/frontend/app/tests/e2e/resource-manager/number-pool.spec.ts
index cb66185ca5..ed4e207fd1 100644
--- a/frontend/app/tests/e2e/resource-manager/number-pool.spec.ts
+++ b/frontend/app/tests/e2e/resource-manager/number-pool.spec.ts
@@ -13,8 +13,8 @@ test.describe("/resource-manager - Resource Manager", () => {
await expect(page.getByText("Name *")).toBeVisible();
await page.getByLabel("Name *").fill("number pool test");
await page.getByLabel("Node *").click();
- await page.getByText("Interface L2", { exact: true }).click();
- await page.getByLabel("Attribute *").click();
+ await page.getByRole("option", { name: "Interface L2 Infra", exact: true }).click();
+ await page.getByText("Number Attribute *").click();
await page.getByRole("option", { name: "Speed" }).click();
await page.getByLabel("Start range *").fill("1");
await page.getByLabel("End range *").fill("10");
diff --git a/frontend/app/tests/e2e/role-management/read.spec.ts b/frontend/app/tests/e2e/role-management/read.spec.ts
new file mode 100644
index 0000000000..7eeb5e11a4
--- /dev/null
+++ b/frontend/app/tests/e2e/role-management/read.spec.ts
@@ -0,0 +1,41 @@
+import { expect, test } from "@playwright/test";
+
+test.describe("Role management - READ", () => {
+ test("should read correctly the different views", async ({ page }) => {
+ await test.step("access main view", async () => {
+ await page.goto("/role-management");
+ });
+
+ await test.step("check counts", async () => {
+ await expect(page.getByRole("link", { name: "Accounts 9" })).toBeVisible();
+ await expect(page.getByRole("link", { name: "Groups 1" })).toBeVisible();
+ await expect(page.getByRole("link", { name: "Roles 1" })).toBeVisible();
+ await expect(page.getByRole("link", { name: "Global Permissions 1" })).toBeVisible();
+ await expect(page.getByRole("link", { name: "Object Permissions 0" })).toBeVisible();
+ });
+
+ await test.step("check accounts view", async () => {
+ await expect(page.getByRole("cell", { name: "Admin" })).toBeVisible();
+ await expect(page.getByRole("cell", { name: "Pop-Builder" })).toBeVisible();
+ });
+
+ await test.step("check groups view", async () => {
+ await page.getByRole("link", { name: "Groups 1" }).click();
+ await expect(page.getByRole("cell", { name: "Administrators" })).toBeVisible();
+ await expect(page.getByRole("cell", { name: "+ 4" })).toBeVisible();
+ });
+
+ await test.step("check roles view", async () => {
+ await page.getByRole("link", { name: "Roles 1" }).click();
+ await expect(page.getByRole("cell", { name: "Super Administrator" })).toBeVisible();
+ await expect(page.getByRole("cell", { name: "1" }).first()).toBeVisible();
+ });
+
+ await test.step("check global permissions view", async () => {
+ await page.getByRole("link", { name: "Global Permissions" }).click();
+ await expect(page.getByRole("cell", { name: "Super Admin" })).toBeVisible();
+ await expect(page.getByRole("cell", { name: "1" }).first()).toBeVisible();
+ await expect(page.getByText("global:super_admin:allow")).toBeVisible();
+ });
+ });
+});
diff --git a/frontend/app/tests/e2e/search.spec.ts b/frontend/app/tests/e2e/search.spec.ts
index f9d1e0f398..9a49ac9560 100644
--- a/frontend/app/tests/e2e/search.spec.ts
+++ b/frontend/app/tests/e2e/search.spec.ts
@@ -13,7 +13,7 @@ test.describe("when searching an object", () => {
await page.goto("/");
await test.step("open search anywhere modal with click", async () => {
- await page.getByPlaceholder("Search anywhere").click();
+ await page.getByTestId("search-anywhere-trigger").click();
await expect(page.getByTestId("search-anywhere")).toBeVisible();
});
@@ -23,17 +23,16 @@ test.describe("when searching an object", () => {
});
await test.step("open search anywhere modal when typing on header input", async () => {
- await page.getByPlaceholder("Search anywhere").fill("e");
+ await page.keyboard.press("Enter");
await expect(page.getByTestId("search-anywhere")).toBeVisible();
});
});
test("displays link to Device list", async ({ page }) => {
await page.goto("/");
- await expect(page.getByTestId("sidebar-menu")).toBeVisible(); // Wait for schema to load
await test.step("open search anywhere modal with click", async () => {
- await page.getByPlaceholder("Search anywhere").click();
+ await page.getByTestId("search-anywhere-trigger").click();
await expect(page.getByTestId("search-anywhere")).toBeVisible();
});
@@ -50,7 +49,7 @@ test.describe("when searching an object", () => {
await page.goto("/");
await test.step("open search anywhere modal", async () => {
- await page.getByPlaceholder("Search anywhere").click();
+ await page.getByTestId("search-anywhere-trigger").click();
await expect(page.getByTestId("search-anywhere")).toBeVisible();
});
@@ -67,7 +66,7 @@ test.describe("when searching an object", () => {
await page.goto("/");
await test.step("open search anywhere modal", async () => {
- await page.getByPlaceholder("Search anywhere").click();
+ await page.getByTestId("search-anywhere-trigger").click();
await expect(page.getByTestId("search-anywhere")).toBeVisible();
});
@@ -86,7 +85,7 @@ test.describe("when searching an object", () => {
const uuid = (await page.locator("dd").first().textContent()) as string;
await test.step("open search anywhere modal", async () => {
- await page.getByPlaceholder("Search anywhere").click();
+ await page.getByTestId("search-anywhere-trigger").click();
await expect(page.getByTestId("search-anywhere")).toBeVisible();
});
diff --git a/frontend/app/tests/e2e/signin.spec.ts b/frontend/app/tests/e2e/signin.spec.ts
index 4960eaa6f8..f8c0d272bd 100644
--- a/frontend/app/tests/e2e/signin.spec.ts
+++ b/frontend/app/tests/e2e/signin.spec.ts
@@ -14,19 +14,21 @@ test.describe("/signin", () => {
test("should log in the user", async ({ page }) => {
await page.goto("/");
- await page.getByRole("link", { name: "Sign in" }).click();
+ await page.getByRole("link", { name: "Log in anonymous" }).click();
+
await expect(page.getByText("Sign in to your account")).toBeVisible();
await page.getByLabel("Username").fill(ADMIN_CREDENTIALS.username);
await page.getByLabel("Password").fill(ADMIN_CREDENTIALS.password);
await page.getByRole("button", { name: "Sign in" }).click();
- await expect(page.getByTestId("current-user-avatar-button")).toBeVisible();
+ await expect(page.getByTestId("authenticated-menu-trigger")).toBeVisible();
});
test("should display an error message when authentication fails", async ({ page }) => {
await page.goto("/");
- await page.getByRole("link", { name: "Sign in" }).click();
+ await page.getByRole("link", { name: "Log in anonymous" }).click();
+
await expect(page.getByText("Sign in to your account")).toBeVisible();
await page.getByLabel("Username").fill("wrong username");
await page.getByLabel("Password").fill("wrong password");
@@ -38,20 +40,19 @@ test.describe("/signin", () => {
});
test("should redirect to the initial page after login", async ({ page }) => {
- await page.goto(
- "/objects/BuiltinTag?branch=atl1-delete-upstream&at=2024-05-01T13%3A40%3A00.000Z"
- );
+ const date = encodeURIComponent(new Date().toISOString());
+ const initialPage = `/objects/BuiltinTag?branch=atl1-delete-upstream&at=${date}`;
+ await page.goto(initialPage);
+
+ await page.getByRole("link", { name: "Log in anonymous" }).click();
- await page.getByRole("link", { name: "Sign in" }).click();
await expect(page.getByText("Sign in to your account")).toBeVisible();
await page.getByLabel("Username").fill(ADMIN_CREDENTIALS.username);
await page.getByLabel("Password").fill(ADMIN_CREDENTIALS.password);
await page.getByRole("button", { name: "Sign in" }).click();
- await expect(page.getByTestId("current-user-avatar-button")).toBeVisible();
- await expect(page.url()).toContain(
- "/objects/BuiltinTag?branch=atl1-delete-upstream&at=2024-05-01T13%3A40%3A00.000Z"
- );
+ await expect(page.getByTestId("authenticated-menu-trigger")).toBeVisible();
+ await expect(page.url()).toContain(initialPage);
});
});
@@ -61,10 +62,10 @@ test.describe("/signin", () => {
test("should log out the user", async ({ page }) => {
await page.goto("/");
- await page.getByTestId("current-user-avatar-button").click();
- await page.getByRole("menuitem", { name: "Sign out" }).click();
+ await page.getByTestId("authenticated-menu-trigger").click();
+ await page.getByRole("menuitem", { name: "Logout" }).click();
- await expect(page.getByRole("link", { name: "Sign in" })).toBeVisible();
+ await expect(page.getByRole("link", { name: "Log in anonymous" })).toBeVisible();
});
test("redirect to homepage if user is already logged in", async ({ page }) => {
@@ -73,7 +74,7 @@ test.describe("/signin", () => {
await expect(page.getByText("Welcome to Infrahub!")).toBeVisible();
});
- test.fixme("should refresh access token and retry failed request", async ({ page }) => {
+ test("should refresh access token and retry failed request", async ({ page }) => {
let blockRequest = true; // force 401 on first call
await page.route("**/graphql/main**", async (route) => {
@@ -101,14 +102,7 @@ test.describe("/signin", () => {
}
});
- const waitForResponse = page.waitForResponse((response) => {
- const reqData = response.request().postDataJSON();
- const status = response.status();
-
- return reqData?.operationName === "BuiltinTag" && status === 200;
- });
-
- await Promise.all([waitForResponse, page.goto("/objects/BuiltinTag")]);
+ await page.goto("/objects/BuiltinTag");
await expect(page.getByRole("cell", { name: "blue" })).toBeVisible();
});
diff --git a/frontend/app/tests/e2e/tutorial/tutorial-1_object-create-update-diff-and-merge.spec.ts b/frontend/app/tests/e2e/tutorial/tutorial-1_object-create-update-diff-and-merge.spec.ts
index 8cf5cfbd10..076d9390ea 100644
--- a/frontend/app/tests/e2e/tutorial/tutorial-1_object-create-update-diff-and-merge.spec.ts
+++ b/frontend/app/tests/e2e/tutorial/tutorial-1_object-create-update-diff-and-merge.spec.ts
@@ -23,6 +23,9 @@ test.describe("Getting started with Infrahub - Object and branch creation, updat
);
await page.goto("/");
+
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Objects" }).click();
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Organization" }).click();
await page.getByTestId("sidebar-menu").getByRole("link", { name: "Tenant" }).click();
await test.step("fill and submit form for new organization", async () => {
@@ -45,6 +48,7 @@ test.describe("Getting started with Infrahub - Object and branch creation, updat
test("2. Create a new branch", async ({ page }) => {
await page.goto("/");
+ await page.getByTestId("branch-selector-trigger").click();
await page.getByTestId("create-branch-button").click();
await test.step("fill and submit form for new organization", async () => {
@@ -55,14 +59,16 @@ test.describe("Getting started with Infrahub - Object and branch creation, updat
});
// After submit
- await expect(page.getByTestId("branch-select-menu")).toContainText("cr1234");
+ await expect(page.getByTestId("branch-selector-trigger")).toContainText("cr1234");
await expect(page).toHaveURL(/.*?branch=cr1234/);
});
test("3. Update an organization", async ({ page }) => {
await test.step("Go to the newly created organization on branch cr1234", async () => {
await page.goto("/?branch=cr1234");
- await page.getByRole("link", { name: "Tenant" }).click();
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Objects" }).click();
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Organization" }).click();
+ await page.getByTestId("sidebar-menu").getByRole("link", { name: "Tenant" }).click();
const myFirstOrgLink = page.getByRole("link", { name: "my-first-tenant" });
await expect(myFirstOrgLink).toBeVisible();
await saveScreenshotForDocs(page, "tutorial_1_organizations");
@@ -86,8 +92,8 @@ test.describe("Getting started with Infrahub - Object and branch creation, updat
});
await test.step("See initial value on main branch", async () => {
- await page.getByTestId("branch-list-display-button").click();
- await page.getByText("main", { exact: true }).click();
+ await page.getByTestId("branch-selector-trigger").click();
+ await page.getByRole("option", { name: "main default" }).click();
await expect(page.getByText("Testing Infrahub")).toBeVisible();
});
});
@@ -95,7 +101,8 @@ test.describe("Getting started with Infrahub - Object and branch creation, updat
test("4. View the Diff and Merge the branch cr1234 into main", async ({ page }) => {
await test.step("Go to branch cr1234 page", async () => {
await page.goto("/?branch=cr1234");
- await page.getByTestId("sidebar-menu").getByRole("link", { name: "Branches" }).click();
+ await page.getByTestId("branch-selector-trigger").click();
+ await page.getByRole("link", { name: "View all branches" }).click();
await saveScreenshotForDocs(page, "tutorial_1_branch_list");
await page.getByTestId("branches-items").getByText("cr1234").click();
await expect(page.locator("dl")).toContainText("cr1234");
@@ -129,9 +136,11 @@ test.describe("Getting started with Infrahub - Object and branch creation, updat
});
await test.step("Validate merged changes in main", async () => {
- await page.getByTestId("branch-list-display-button").click();
- await page.getByTestId("branch-list-dropdown").getByText("main", { exact: true }).click();
- await expect(page.getByTestId("branch-list-display-button")).toContainText("main");
+ await page.getByTestId("branch-selector-trigger").click();
+ await page.getByRole("option", { name: "main default" }).click();
+ await expect(page.getByTestId("branch-selector-trigger")).toContainText("main");
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Objects" }).click();
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Organization" }).click();
await page.getByTestId("sidebar-menu").getByRole("link", { name: "Tenant" }).click();
await expect(page.locator("tbody")).toContainText("Changes from branch cr1234");
});
diff --git a/frontend/app/tests/e2e/tutorial/tutorial-3_schema.spec.ts b/frontend/app/tests/e2e/tutorial/tutorial-3_schema.spec.ts
index 74bbb4cb97..5a31b48f3b 100644
--- a/frontend/app/tests/e2e/tutorial/tutorial-3_schema.spec.ts
+++ b/frontend/app/tests/e2e/tutorial/tutorial-3_schema.spec.ts
@@ -15,6 +15,7 @@ test.describe("Getting started with Infrahub - Data lineage and metadata", () =>
test("1. Visualize the active schema", async ({ page }) => {
await page.goto("/");
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Unified Storage" }).click();
await page.getByTestId("sidebar-menu").getByRole("link", { name: "Schema" }).click();
await expect(page.getByText("Artifact Check")).toBeVisible();
await saveScreenshotForDocs(page, "tutorial_3_schema");
diff --git a/frontend/app/tests/e2e/tutorial/tutorial-4_integration-with-git.spec.ts b/frontend/app/tests/e2e/tutorial/tutorial-4_integration-with-git.spec.ts
index 6288edc7a8..0003d4d7b9 100644
--- a/frontend/app/tests/e2e/tutorial/tutorial-4_integration-with-git.spec.ts
+++ b/frontend/app/tests/e2e/tutorial/tutorial-4_integration-with-git.spec.ts
@@ -17,21 +17,24 @@ test.describe("Getting started with Infrahub - Integration with Git", () => {
await page.goto("/");
await test.step(" Create a new branch update-ethernet1", async () => {
+ await page.getByTestId("branch-selector-trigger").click();
await page.getByTestId("create-branch-button").click();
await page.getByLabel("New branch name").fill("update-ethernet1");
await page.getByLabel("Sync with Git").click();
await saveScreenshotForDocs(page, "tutorial_6_branch_creation");
await page.getByRole("button", { name: "Create" }).click();
- await expect(page.getByTestId("branch-select-menu")).toContainText("update-ethernet1");
+ await expect(page.getByTestId("branch-selector-trigger")).toContainText("update-ethernet1");
});
await test.step("go to interface Ethernet 1 for atl1-edge1", async () => {
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Objects" }).click();
+ await page.getByTestId("sidebar-menu").getByRole("button", { name: "Device" }).click();
await page.getByRole("link", { name: "All Device(s)" }).click();
await expect(page.getByText("Generic Device object")).toBeVisible();
await page.getByRole("link", { name: "atl1-edge1" }).click();
await page.getByText("Interfaces15").click();
- await page.getByRole("link", { name: "Connected to atl1-edge2 Ethernet1" }).click();
+ await page.getByRole("link", { name: "Connected to atl1-edge2::Ethernet1" }).click();
});
await test.step("Update the interface Ethernet 1 for atl1-edge1", async () => {
diff --git a/frontend/app/tests/fixtures/config.json b/frontend/app/tests/fixtures/config.json
index 2dd55adad9..be5994847d 100644
--- a/frontend/app/tests/fixtures/config.json
+++ b/frontend/app/tests/fixtures/config.json
@@ -1,7 +1,12 @@
{
"main": {
- "default_branch": "another-branch",
- "internal_address": "http://infrahub-server:8000"
+ "docs_index_path": "/opt/infrahub/docs/build/search-index.json",
+ "internal_address": "http://infrahub-server:8000",
+ "allow_anonymous_access": false,
+ "telemetry_optout": false,
+ "telemetry_endpoint": "https://telemetry.opsmill.cloud/infrahub",
+ "telemetry_interval": 86400,
+ "permission_backends": ["infrahub.permissions.LocalPermissionBackend"]
},
"logging": {
"remote": {
@@ -18,6 +23,10 @@
},
"experimental_features": {
"pull_request": false,
- "paginated": false
+ "graphql_enums": false
+ },
+ "sso": {
+ "enabled": false,
+ "providers": []
}
}
diff --git a/frontend/app/tests/fixtures/schema.json b/frontend/app/tests/fixtures/schema.json
index 94fb27fa83..b157d6b315 100644
--- a/frontend/app/tests/fixtures/schema.json
+++ b/frontend/app/tests/fixtures/schema.json
@@ -75,36 +75,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 100000
},
{
@@ -119,36 +89,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 101000
},
{
@@ -163,36 +103,6 @@
"cardinality": "one",
"branch": "aware",
"optional": false,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "label__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 102000
},
{
@@ -207,50 +117,6 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "speed__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "mtu__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "enabled__value",
- "kind": "Boolean",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 103000
},
{
@@ -265,36 +131,6 @@
"cardinality": "one",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "asn__value",
- "kind": "Number",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 104000
},
{
@@ -309,101 +145,13 @@
"cardinality": "many",
"branch": "aware",
"optional": true,
- "filters": [
- {
- "name": "id",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- }
- ],
"order_weight": 105000
}
],
"label": "Device",
"inherit_from": [],
"groups": [],
- "branch": "aware",
- "filters": [
- {
- "name": "ids",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "name__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "description__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "type__value",
- "kind": "Text",
- "enum": null,
- "object_kind": null,
- "description": null
- },
- {
- "name": "site__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "Location",
- "description": null
- },
- {
- "name": "status__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "Status",
- "description": null
- },
- {
- "name": "role__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "Role",
- "description": null
- },
- {
- "name": "asn__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "AutonomousSystem",
- "description": null
- },
- {
- "name": "tags__id",
- "kind": "Object",
- "enum": null,
- "object_kind": "Tag",
- "description": null
- }
- ]
+ "branch": "aware"
}
]
}
diff --git a/frontend/app/tests/integrations/screens/account.cy.tsx b/frontend/app/tests/integrations/screens/account.cy.tsx
index 70356b49e6..a08256e2c4 100644
--- a/frontend/app/tests/integrations/screens/account.cy.tsx
+++ b/frontend/app/tests/integrations/screens/account.cy.tsx
@@ -2,10 +2,9 @@
import { MockedProvider } from "@apollo/client/testing";
import React from "react";
-import { initials } from "../../../src/components/display/avatar";
+import { AccountMenu } from "../../../src/components/account-menu";
import { ACCESS_TOKEN_KEY } from "../../../src/config/constants";
import { AuthProvider } from "../../../src/hooks/useAuth";
-import Header from "../../../src/screens/layout/header";
import { genericsState } from "../../../src/state/atoms/schema.atom";
import { encodeJwt } from "../../../src/utils/common";
import { accountDetailsMocksSchema } from "../../mocks/data/account";
@@ -21,7 +20,7 @@ const mocks = [
{
request: {
query: profileDetailsMocksQuery,
- variables: { offset: 0, limit: 10 },
+ variables: {},
},
result: {
data: profileDetailsMocksData,
@@ -31,7 +30,7 @@ const mocks = [
const AuthHeader = () => (
-
+
);
@@ -56,9 +55,6 @@ describe("List screen", () => {
);
- cy.get(".h-12").should(
- "have.text",
- initials(profileDetailsMocksData.AccountProfile.display_label)
- );
+ cy.contains(profileDetailsMocksData.AccountProfile.display_label);
});
});
diff --git a/frontend/app/tests/integrations/screens/app-init.cy.tsx b/frontend/app/tests/integrations/screens/app-init.cy.tsx
index 923eb0ea7f..521e334f68 100644
--- a/frontend/app/tests/integrations/screens/app-init.cy.tsx
+++ b/frontend/app/tests/integrations/screens/app-init.cy.tsx
@@ -1,9 +1,9 @@
///
import { MockedProvider } from "@apollo/client/testing";
+import { mount } from "cypress/react18";
import React from "react";
import { App } from "../../../src/App";
-import { mount } from "cypress/react18";
describe("Config fetch", () => {
beforeEach(function () {
diff --git a/frontend/app/tests/integrations/screens/artifact-diff.cy.tsx b/frontend/app/tests/integrations/screens/artifact-diff.cy.tsx
index ccd950b826..f52bd15565 100644
--- a/frontend/app/tests/integrations/screens/artifact-diff.cy.tsx
+++ b/frontend/app/tests/integrations/screens/artifact-diff.cy.tsx
@@ -55,7 +55,8 @@ const ArtifactsDiffProvider = ({ loggedIn }: { loggedIn: boolean }) => {
initialValues={[
[schemaState, [...artifactThreadSchema, ...accountDetailsMocksSchema]],
[proposedChangedState, proposedChangesDetails],
- ]}>
+ ]}
+ >
{loggedIn ? : }
);
diff --git a/frontend/app/tests/integrations/screens/conversations.cy.tsx b/frontend/app/tests/integrations/screens/conversations.cy.tsx
index 248717298d..197e53880a 100644
--- a/frontend/app/tests/integrations/screens/conversations.cy.tsx
+++ b/frontend/app/tests/integrations/screens/conversations.cy.tsx
@@ -42,7 +42,8 @@ const ConversationsProvider = () => {
initialValues={[
[schemaState, [...conversationMocksSchema, ...accountDetailsMocksSchema]],
[proposedChangedState, proposedChangesDetails],
- ]}>
+ ]}
+ >
);
diff --git a/frontend/app/tests/integrations/screens/object-details-relationships.cy.tsx b/frontend/app/tests/integrations/screens/object-details-relationships.cy.tsx
index 8e8f3c3bec..bef382d54d 100644
--- a/frontend/app/tests/integrations/screens/object-details-relationships.cy.tsx
+++ b/frontend/app/tests/integrations/screens/object-details-relationships.cy.tsx
@@ -4,6 +4,7 @@ import { gql } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";
import React from "react";
import { Route, Routes } from "react-router-dom";
+import { ObjectDetailsPage } from "../../../src/pages/objects/object-details";
import { genericsState, schemaState } from "../../../src/state/atoms/schema.atom";
import {
deviceDetailsInterfacesMocksData,
@@ -18,7 +19,6 @@ import {
interfacesArrayCount,
} from "../../mocks/data/devices";
import { TestProvider } from "../../mocks/jotai/atom";
-import { ObjectDetailsPage } from "../../../src/pages/objects/object-details";
// URL for the current view
const graphqlQueryItemsUrl = `/objects/InfraDevice/${deviceDetailsMocksId}`;
@@ -95,7 +95,8 @@ const ObjectDetailsProvider = () => {
initialValues={[
[schemaState, deviceDetailsMocksSchema],
[genericsState, deviceDetailsMocksGenerics],
- ]}>
+ ]}
+ >
);
diff --git a/frontend/app/tests/integrations/screens/object-details.cy.tsx b/frontend/app/tests/integrations/screens/object-details.cy.tsx
index e2454405aa..6f420c7831 100644
--- a/frontend/app/tests/integrations/screens/object-details.cy.tsx
+++ b/frontend/app/tests/integrations/screens/object-details.cy.tsx
@@ -4,6 +4,7 @@ import { gql } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";
import React from "react";
import { Route, Routes } from "react-router-dom";
+import { ObjectDetailsPage } from "../../../src/pages/objects/object-details";
import { schemaState } from "../../../src/state/atoms/schema.atom";
import {
deviceDetailsMocksASNName,
@@ -15,7 +16,6 @@ import {
deviceDetailsMocksTagName,
} from "../../mocks/data/devices";
import { TestProvider } from "../../mocks/jotai/atom";
-import { ObjectDetailsPage } from "../../../src/pages/objects/object-details";
// URL for the current view
const graphqlQueryItemsUrl = `/objects/InfraDevice/${deviceDetailsMocksId}`;
diff --git a/frontend/app/tests/integrations/screens/object-fields.cy.tsx b/frontend/app/tests/integrations/screens/object-fields.cy.tsx
index daa75f28be..3059f460d4 100644
--- a/frontend/app/tests/integrations/screens/object-fields.cy.tsx
+++ b/frontend/app/tests/integrations/screens/object-fields.cy.tsx
@@ -12,8 +12,8 @@ import { encodeJwt } from "../../../src/utils/common";
import { accountDetailsMocksSchema } from "../../mocks/data/account";
import {
profileDetailsMocksData,
- profilesDetailsMocksQuery,
profileId,
+ profilesDetailsMocksQuery,
} from "../../mocks/data/account-profile";
import {
taskMocksData as taskMocksData1,
@@ -47,8 +47,10 @@ import {
taskMocksSchema as taskMocksSchema5,
} from "../../mocks/data/task_5";
+import { ObjectItemsPage } from "../../../src/pages/objects/object-items";
import { ipamIpAddressMocksSchema } from "../../mocks/data/ip-address";
import { ipPrefixMocksSchema } from "../../mocks/data/ip-prefix";
+import { numberPoolData, numberPoolQuery } from "../../mocks/data/number-pool";
import {
taskMocksData as taskMocksData6,
taskMocksQuery as taskMocksQuery6,
@@ -60,8 +62,6 @@ import {
taskMocksSchema as taskMocksSchema7,
} from "../../mocks/data/task_7";
import { TestProvider } from "../../mocks/jotai/atom";
-import { ObjectItemsPage } from "../../../src/pages/objects/object-items";
-import { numberPoolData, numberPoolQuery } from "../../mocks/data/number-pool";
// URL for the current view
const mockedUrl = "/objects/TestTask";
@@ -196,7 +196,8 @@ describe("Object list", () => {
const ObjectItemsProvider = () => {
return (
+ initialValues={[[schemaState, [...accountDetailsMocksSchema, ...taskMocksSchema1]]]}
+ >
);
@@ -238,7 +239,8 @@ describe("Object list", () => {
+ ]}
+ >
);
@@ -280,7 +282,8 @@ describe("Object list", () => {
+ ]}
+ >
);
@@ -320,7 +323,8 @@ describe("Object list", () => {
const ObjectItemsProvider = () => {
return (
+ initialValues={[[schemaState, [...accountDetailsMocksSchema, ...taskMocksSchema2]]]}
+ >
);
@@ -362,7 +366,8 @@ describe("Object list", () => {
+ ]}
+ >
);
@@ -404,7 +409,8 @@ describe("Object list", () => {
+ ]}
+ >
);
@@ -444,7 +450,8 @@ describe("Object list", () => {
const ObjectItemsProvider = () => {
return (
+ initialValues={[[schemaState, [...accountDetailsMocksSchema, ...taskMocksSchema3]]]}
+ >
);
@@ -484,7 +491,8 @@ describe("Object list", () => {
const ObjectItemsProvider = () => {
return (
+ initialValues={[[schemaState, [...accountDetailsMocksSchema, ...taskMocksSchema3]]]}
+ >
);
@@ -529,7 +537,8 @@ describe("Object list", () => {
+ ]}
+ >
);
@@ -571,7 +580,8 @@ describe("Object list", () => {
+ ]}
+ >
);
@@ -611,7 +621,8 @@ describe("Object list", () => {
const ObjectItemsProvider = () => {
return (
+ initialValues={[[schemaState, [...accountDetailsMocksSchema, ...taskMocksSchema4]]]}
+ >
);
@@ -651,7 +662,8 @@ describe("Object list", () => {
const ObjectItemsProvider = () => {
return (
+ initialValues={[[schemaState, [...accountDetailsMocksSchema, ...taskMocksSchema5]]]}
+ >
);
@@ -701,7 +713,8 @@ describe("Object list", () => {
ipamIpAddressMocksSchema,
],
],
- ]}>
+ ]}
+ >
);
@@ -737,7 +750,8 @@ describe("Object list", () => {
const ObjectItemsProvider = () => {
return (
+ initialValues={[[schemaState, [...accountDetailsMocksSchema, ...taskMocksSchema7]]]}
+ >
);
diff --git a/frontend/app/tests/integrations/screens/object-items-deletion.cy.tsx b/frontend/app/tests/integrations/screens/object-items-deletion.cy.tsx
index b1b7455d96..af7fabce76 100644
--- a/frontend/app/tests/integrations/screens/object-items-deletion.cy.tsx
+++ b/frontend/app/tests/integrations/screens/object-items-deletion.cy.tsx
@@ -6,6 +6,7 @@ import React from "react";
import { Route, Routes } from "react-router-dom";
import { ACCESS_TOKEN_KEY } from "../../../src/config/constants";
import { AuthProvider } from "../../../src/hooks/useAuth";
+import { ObjectItemsPage } from "../../../src/pages/objects/object-items";
import { configState } from "../../../src/state/atoms/config.atom";
import { schemaState } from "../../../src/state/atoms/schema.atom";
import { mockedToken } from "../../fixtures/auth";
@@ -18,7 +19,6 @@ import {
} from "../../mocks/data/graphqlQueries";
import { schemaMocks } from "../../mocks/data/schema";
import { TestProvider } from "../../mocks/jotai/atom";
-import { ObjectItemsPage } from "../../../src/pages/objects/object-items";
// URL for the current view
const mockedUrl = "/objects/CoreGraphQLQuery";
@@ -67,7 +67,8 @@ const ObjectItemsProvider = () => {
initialValues={[
[schemaState, schemaMocks],
[configState, configMocks],
- ]}>
+ ]}
+ >
);
diff --git a/frontend/app/tests/integrations/screens/object-items.cy.tsx b/frontend/app/tests/integrations/screens/object-items.cy.tsx
index 89633dee07..8f78299c55 100644
--- a/frontend/app/tests/integrations/screens/object-items.cy.tsx
+++ b/frontend/app/tests/integrations/screens/object-items.cy.tsx
@@ -4,6 +4,7 @@ import { gql } from "@apollo/client";
import { MockedProvider } from "@apollo/client/testing";
import React from "react";
import { Route, Routes } from "react-router-dom";
+import { ObjectItemsPage } from "../../../src/pages/objects/object-items";
import { genericsState, schemaState } from "../../../src/state/atoms/schema.atom";
import {
graphqlQueriesMocksData,
@@ -12,7 +13,6 @@ import {
} from "../../mocks/data/graphqlQueries";
import { schemaMocks } from "../../mocks/data/schema";
import { TestProvider } from "../../mocks/jotai/atom";
-import { ObjectItemsPage } from "../../../src/pages/objects/object-items";
// URL for the current view
const mockedUrl = "/objects/CoreGraphQLQuery";
@@ -111,7 +111,8 @@ describe("List screen", () => {
initialValues={[
[schemaState, []],
[genericsState, schemaMocks],
- ]}>
+ ]}
+ >
);
diff --git a/frontend/app/tests/mocks/data/config.ts b/frontend/app/tests/mocks/data/config.ts
index 62bd4f5680..53630e91aa 100644
--- a/frontend/app/tests/mocks/data/config.ts
+++ b/frontend/app/tests/mocks/data/config.ts
@@ -1,7 +1,12 @@
export const configMocks = {
main: {
- default_branch: "main",
+ docs_index_path: "/opt/infrahub/docs/build/search-index.json",
internal_address: "http://infrahub-server:8000",
+ allow_anonymous_access: true,
+ telemetry_optout: false,
+ telemetry_endpoint: "https://telemetry.opsmill.cloud/infrahub",
+ telemetry_interval: 86400,
+ permission_backends: ["infrahub.permissions.LocalPermissionBackend"],
},
logging: {
remote: {
@@ -18,6 +23,10 @@ export const configMocks = {
},
experimental_features: {
pull_request: false,
- paginated: true,
+ graphql_enums: false,
+ },
+ sso: {
+ providers: [],
+ enabled: false,
},
};
diff --git a/frontend/app/tests/unit/components/branch-list.test.tsx b/frontend/app/tests/unit/components/branch-list.test.tsx
index 6e686d1168..84ea1101f2 100644
--- a/frontend/app/tests/unit/components/branch-list.test.tsx
+++ b/frontend/app/tests/unit/components/branch-list.test.tsx
@@ -33,7 +33,8 @@ describe("Branch list", () => {
options={{
searchStringToObject: queryString.parse,
objectToSearchString: queryString.stringify,
- }}>
+ }}
+ >
diff --git a/frontend/app/tests/unit/components/branch-selector.test.tsx b/frontend/app/tests/unit/components/branch-selector.test.tsx
index af3df9a775..f737c9e8ec 100644
--- a/frontend/app/tests/unit/components/branch-selector.test.tsx
+++ b/frontend/app/tests/unit/components/branch-selector.test.tsx
@@ -18,7 +18,8 @@ describe("Branch selector", () => {
options={{
searchStringToObject: queryString.parse,
objectToSearchString: queryString.stringify,
- }}>
+ }}
+ >
diff --git a/frontend/app/tests/unit/components/filters/getFiltersFromFormData.test.ts b/frontend/app/tests/unit/components/filters/getFiltersFromFormData.test.ts
index 707903dd25..475790377b 100644
--- a/frontend/app/tests/unit/components/filters/getFiltersFromFormData.test.ts
+++ b/frontend/app/tests/unit/components/filters/getFiltersFromFormData.test.ts
@@ -1,6 +1,6 @@
-import { describe, expect } from "vitest";
-import { FormFieldValue } from "@/components/form/type";
import { getFiltersFromFormData } from "@/components/filters/utils/getFiltersFromFormData";
+import { FormFieldValue } from "@/components/form/type";
+import { describe, expect } from "vitest";
describe("getFiltersFromFormData - test", () => {
it("returns an attribute value correctly", () => {
diff --git a/frontend/app/tests/unit/components/filters/getObjectFromFilters.test.ts b/frontend/app/tests/unit/components/filters/getObjectFromFilters.test.ts
index ea04c53b8c..7ff9ec361a 100644
--- a/frontend/app/tests/unit/components/filters/getObjectFromFilters.test.ts
+++ b/frontend/app/tests/unit/components/filters/getObjectFromFilters.test.ts
@@ -1,7 +1,7 @@
-import { describe, expect } from "vitest";
import { getObjectFromFilters } from "@/components/filters/utils/getObjectFromFilters";
import { Filter } from "@/hooks/useFilters";
import { IModelSchema } from "@/state/atoms/schema.atom";
+import { describe, expect } from "vitest";
import { buildRelationshipSchema } from "../form/utils/getFormFieldsFromSchema.test";
describe("getObjectFromFilters - test", () => {
diff --git a/frontend/app/tests/unit/components/form/utils/getCreateMutationFromFormData.test.ts b/frontend/app/tests/unit/components/form/utils/getCreateMutationFromFormData.test.ts
index c26536840e..479c534aab 100644
--- a/frontend/app/tests/unit/components/form/utils/getCreateMutationFromFormData.test.ts
+++ b/frontend/app/tests/unit/components/form/utils/getCreateMutationFromFormData.test.ts
@@ -1,11 +1,11 @@
-import { describe, expect } from "vitest";
import {
+ AttributeValueFromProfile,
DynamicFieldProps,
FormAttributeValue,
FormRelationshipValue,
- AttributeValueFromProfile,
} from "@/components/form/type";
import { getCreateMutationFromFormData } from "@/components/form/utils/mutations/getCreateMutationFromFormData";
+import { describe, expect } from "vitest";
export const buildField = (override?: Partial): DynamicFieldProps => {
return {
diff --git a/frontend/app/tests/unit/components/form/utils/getFieldDefaultValue.test.ts b/frontend/app/tests/unit/components/form/utils/getFieldDefaultValue.test.ts
index 45cbee01dc..5c3b6262a7 100644
--- a/frontend/app/tests/unit/components/form/utils/getFieldDefaultValue.test.ts
+++ b/frontend/app/tests/unit/components/form/utils/getFieldDefaultValue.test.ts
@@ -1,11 +1,11 @@
-import { describe, expect, it } from "vitest";
+import { ProfileData } from "@/components/form/object-form";
import {
GetFieldDefaultValue,
getFieldDefaultValue,
} from "@/components/form/utils/getFieldDefaultValue";
-import { ProfileData } from "@/components/form/object-form";
-import { buildAttributeSchema, buildRelationshipSchema } from "./getFormFieldsFromSchema.test";
import { AttributeType } from "@/utils/getObjectItemDisplayValue";
+import { describe, expect, it } from "vitest";
+import { buildAttributeSchema, buildRelationshipSchema } from "./getFormFieldsFromSchema.test";
describe("getFieldDefaultValue", () => {
describe("when source is the user", () => {
diff --git a/frontend/app/tests/unit/components/form/utils/getFormFieldsFromSchema.test.ts b/frontend/app/tests/unit/components/form/utils/getFormFieldsFromSchema.test.ts
index 2e367f24f2..67882d2e8e 100644
--- a/frontend/app/tests/unit/components/form/utils/getFormFieldsFromSchema.test.ts
+++ b/frontend/app/tests/unit/components/form/utils/getFormFieldsFromSchema.test.ts
@@ -1,9 +1,9 @@
-import { describe, expect, it } from "vitest";
import { getFormFieldsFromSchema } from "@/components/form/utils/getFormFieldsFromSchema";
-import { IModelSchema } from "@/state/atoms/schema.atom";
import { AuthContextType } from "@/hooks/useAuth";
-import { AttributeType } from "@/utils/getObjectItemDisplayValue";
import { components } from "@/infraops";
+import { IModelSchema } from "@/state/atoms/schema.atom";
+import { AttributeType } from "@/utils/getObjectItemDisplayValue";
+import { describe, expect, it } from "vitest";
export const buildAttributeSchema = (
override?: Partial
@@ -267,16 +267,16 @@ describe("getFormFieldsFromSchema", () => {
},
items: [
{
- id: "prefix",
+ value: "prefix",
+ label: "Prefix",
description: "Prefix serves as container for other prefixes",
color: "#ed6a5a",
- name: "Prefix",
},
{
- id: "address",
+ value: "address",
+ label: "Address",
description: "Prefix serves as subnet for IP addresses",
color: "#f4f1bb",
- name: "Address",
},
],
field: schema.attributes?.[0],
@@ -316,11 +316,7 @@ describe("getFormFieldsFromSchema", () => {
required: expect.any(Function),
},
},
- items: [
- { id: 1, name: 1 },
- { id: 2, name: 2 },
- { id: 3, name: 3 },
- ],
+ items: [1, 2, 3],
field: schema.attributes?.[0],
schema,
unique: false,
diff --git a/frontend/app/tests/unit/components/form/utils/getRelationshipDefaultValue.test.ts b/frontend/app/tests/unit/components/form/utils/getRelationshipDefaultValue.test.ts
index 0d2f419145..90b19c27b5 100644
--- a/frontend/app/tests/unit/components/form/utils/getRelationshipDefaultValue.test.ts
+++ b/frontend/app/tests/unit/components/form/utils/getRelationshipDefaultValue.test.ts
@@ -1,7 +1,7 @@
-import { describe, expect, vi } from "vitest";
import { getRelationshipDefaultValue } from "@/components/form/utils/getRelationshipDefaultValue";
-import { RelationshipManyType, RelationshipOneType } from "@/utils/getObjectItemDisplayValue";
import { RESOURCE_GENERIC_KIND } from "@/screens/resource-manager/constants";
+import { RelationshipManyType, RelationshipOneType } from "@/utils/getObjectItemDisplayValue";
+import { describe, expect, vi } from "vitest";
const buildRelationshipOneData = (override: Partial): RelationshipOneType => ({
node: {
diff --git a/frontend/app/tests/unit/components/form/utils/getRelationshipsForForm.test.ts b/frontend/app/tests/unit/components/form/utils/getRelationshipsForForm.test.ts
index 4509a6d363..8a5063a4c0 100644
--- a/frontend/app/tests/unit/components/form/utils/getRelationshipsForForm.test.ts
+++ b/frontend/app/tests/unit/components/form/utils/getRelationshipsForForm.test.ts
@@ -1,5 +1,5 @@
-import { describe, expect, it } from "vitest";
import { getRelationshipsForForm } from "@/components/form/utils/getRelationshipsForForm";
+import { describe, expect, it } from "vitest";
import { buildRelationshipSchema } from "./getFormFieldsFromSchema.test";
describe("getRelationshipsForForm", () => {
diff --git a/frontend/app/tests/unit/components/form/utils/getUpdateMutationFromFormData.test.ts b/frontend/app/tests/unit/components/form/utils/getUpdateMutationFromFormData.test.ts
index 5180f68111..bd70c27673 100644
--- a/frontend/app/tests/unit/components/form/utils/getUpdateMutationFromFormData.test.ts
+++ b/frontend/app/tests/unit/components/form/utils/getUpdateMutationFromFormData.test.ts
@@ -1,10 +1,10 @@
-import { describe, expect } from "vitest";
import {
DynamicFieldProps,
FormAttributeValue,
RelationshipValueFormPool,
} from "@/components/form/type";
import { getUpdateMutationFromFormData } from "@/components/form/utils/mutations/getUpdateMutationFromFormData";
+import { describe, expect } from "vitest";
import { buildField } from "./getCreateMutationFromFormData.test";
describe("getUpdateMutationFromFormData - test", () => {
diff --git a/frontend/app/tests/unit/components/form/utils/isFieldDisabled.test.ts b/frontend/app/tests/unit/components/form/utils/isFieldDisabled.test.ts
index 9d42929689..952420bb82 100644
--- a/frontend/app/tests/unit/components/form/utils/isFieldDisabled.test.ts
+++ b/frontend/app/tests/unit/components/form/utils/isFieldDisabled.test.ts
@@ -1,5 +1,5 @@
+import { IsFieldDisabledParams, isFieldDisabled } from "@/components/form/utils/isFieldDisabled";
import { describe, expect, it } from "vitest";
-import { isFieldDisabled, IsFieldDisabledParams } from "@/components/form/utils/isFieldDisabled";
describe("isFieldDisabled", () => {
it("returns true when field is read only", () => {
diff --git a/frontend/app/tests/unit/components/tree/addItemsToTree.test.ts b/frontend/app/tests/unit/components/tree/addItemsToTree.test.ts
index e836ace843..34d770f9ab 100644
--- a/frontend/app/tests/unit/components/tree/addItemsToTree.test.ts
+++ b/frontend/app/tests/unit/components/tree/addItemsToTree.test.ts
@@ -1,8 +1,8 @@
-import { describe, it, expect } from "vitest";
-import { addItemsToTree } from "@/screens/ipam/ipam-tree/utils";
-import { EMPTY_TREE } from "@/screens/ipam/ipam-tree/utils";
import { TreeProps } from "@/components/ui/tree";
import { TREE_ROOT_ID } from "@/screens/ipam/constants";
+import { addItemsToTree } from "@/screens/ipam/ipam-tree/utils";
+import { EMPTY_TREE } from "@/screens/ipam/ipam-tree/utils";
+import { describe, expect, it } from "vitest";
describe("Add items to tree", () => {
it("should return the original tree when no items are provided", () => {
diff --git a/frontend/app/tests/unit/diff/diff-tree/formatDiffNodesToDiffTree.test.ts b/frontend/app/tests/unit/diff/diff-tree/formatDiffNodesToDiffTree.test.ts
index e57f39b5a6..e7b90b0743 100644
--- a/frontend/app/tests/unit/diff/diff-tree/formatDiffNodesToDiffTree.test.ts
+++ b/frontend/app/tests/unit/diff/diff-tree/formatDiffNodesToDiffTree.test.ts
@@ -1,4 +1,4 @@
-import { describe, it, expect } from "vitest";
+import { describe, expect, it } from "vitest";
import { formatDiffNodesToDiffTree } from "../../../../src/screens/diff/diff-tree";
import { DiffNode } from "../../../../src/screens/diff/node-diff/types";
import { TREE_ROOT_ID } from "../../../../src/screens/ipam/constants";
diff --git a/frontend/app/tests/unit/diff/diff-tree/generateRootCategoryNodeForDiffTree.test.ts b/frontend/app/tests/unit/diff/diff-tree/generateRootCategoryNodeForDiffTree.test.ts
index 051d3cb6e9..6ca93572f7 100644
--- a/frontend/app/tests/unit/diff/diff-tree/generateRootCategoryNodeForDiffTree.test.ts
+++ b/frontend/app/tests/unit/diff/diff-tree/generateRootCategoryNodeForDiffTree.test.ts
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
-import { generateRootCategoryNodeForDiffTree } from "../../../../src/screens/diff/diff-tree";
import { TreeProps } from "../../../../src/components/ui/tree";
+import { generateRootCategoryNodeForDiffTree } from "../../../../src/screens/diff/diff-tree";
import { TREE_ROOT_ID } from "../../../../src/screens/ipam/constants";
describe("Generate root category nodes for DiffTree", () => {
diff --git a/frontend/app/tests/utils.ts b/frontend/app/tests/utils.ts
index 3ff42043d5..816ed3ff02 100644
--- a/frontend/app/tests/utils.ts
+++ b/frontend/app/tests/utils.ts
@@ -11,10 +11,11 @@ export const saveScreenshotForDocs = async (page: Page, filename: string) => {
};
export const createBranch = async (page: Page, branchName: string) => {
+ await page.getByTestId("branch-selector-trigger").click();
await page.getByTestId("create-branch-button").click();
await page.getByLabel("New branch name *").fill(branchName);
await page.getByRole("button", { name: "Create a new branch" }).click();
- await expect(page.getByTestId("branch-list-display-button")).toContainText(branchName);
+ await expect(page.getByTestId("branch-selector-trigger")).toContainText(branchName);
};
export const deleteBranch = async (page: Page, branchName: string) => {
diff --git a/frontend/app/tsconfig.json b/frontend/app/tsconfig.json
index e71872264a..fc9b09f9a5 100644
--- a/frontend/app/tsconfig.json
+++ b/frontend/app/tsconfig.json
@@ -1,21 +1,11 @@
{
"compilerOptions": {
"paths": {
- "@/*": [
- "./src/*"
- ]
+ "@/*": ["./src/*"]
},
"target": "ESNext",
- "lib": [
- "dom",
- "dom.iterable",
- "esnext"
- ],
- "types": [
- "vite/client",
- "vitest/globals",
- "cypress"
- ],
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "types": ["vite/client", "vitest/globals", "cypress"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
@@ -45,5 +35,5 @@
"tests/unit/utils",
"tests/unit/data",
"tests/integrations/tests"
- ],
-}
\ No newline at end of file
+ ]
+}
diff --git a/frontend/packages/plugins/template/package-lock.json b/frontend/packages/plugins/template/package-lock.json
index f8116e011e..fcd2886d9a 100644
--- a/frontend/packages/plugins/template/package-lock.json
+++ b/frontend/packages/plugins/template/package-lock.json
@@ -392,13 +392,14 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
- "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [
"ppc64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"aix"
@@ -408,13 +409,14 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
- "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -424,13 +426,14 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
- "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -440,13 +443,14 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
- "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
@@ -456,13 +460,14 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
- "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -472,13 +477,14 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
- "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -488,13 +494,14 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
- "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"freebsd"
@@ -504,13 +511,14 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
- "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"freebsd"
@@ -520,13 +528,14 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
- "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -536,13 +545,14 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
- "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -552,13 +562,14 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
- "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [
"ia32"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -568,13 +579,14 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
- "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [
"loong64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -584,13 +596,14 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
- "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [
"mips64el"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -600,13 +613,14 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
- "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [
"ppc64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -616,13 +630,14 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
- "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [
"riscv64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -632,13 +647,14 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
- "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [
"s390x"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -648,13 +664,14 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
- "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -664,13 +681,14 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
- "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"netbsd"
@@ -680,13 +698,14 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
- "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"openbsd"
@@ -696,13 +715,14 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
- "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"sunos"
@@ -712,13 +732,14 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
- "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -728,13 +749,14 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
- "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [
"ia32"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -744,13 +766,14 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
- "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1030,208 +1053,224 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
- "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz",
+ "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz",
- "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz",
+ "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz",
- "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz",
+ "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz",
- "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz",
+ "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz",
- "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz",
+ "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz",
- "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz",
+ "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz",
- "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz",
+ "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz",
- "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz",
+ "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz",
- "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz",
+ "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==",
"cpu": [
"ppc64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz",
- "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz",
+ "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==",
"cpu": [
"riscv64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz",
- "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz",
+ "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==",
"cpu": [
"s390x"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz",
- "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz",
+ "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz",
- "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz",
+ "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz",
- "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz",
+ "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz",
- "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz",
+ "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==",
"cpu": [
"ia32"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz",
- "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz",
+ "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1705,20 +1744,6 @@
"@esbuild/win32-x64": "0.18.20"
}
},
- "node_modules/@softarc/native-federation-esbuild/node_modules/rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
- "bin": {
- "rollup": "dist/bin/rollup"
- },
- "engines": {
- "node": ">=10.0.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
"node_modules/@softarc/native-federation-esbuild/node_modules/rollup-plugin-node-externals": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-externals/-/rollup-plugin-node-externals-4.1.1.tgz",
@@ -1783,9 +1808,10 @@
}
},
"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=="
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "license": "MIT"
},
"node_modules/@types/node": {
"version": "20.14.0",
@@ -2375,11 +2401,12 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/esbuild": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
- "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true,
"hasInstallScript": true,
+ "license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
@@ -2387,29 +2414,29 @@
"node": ">=12"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.20.2",
- "@esbuild/android-arm": "0.20.2",
- "@esbuild/android-arm64": "0.20.2",
- "@esbuild/android-x64": "0.20.2",
- "@esbuild/darwin-arm64": "0.20.2",
- "@esbuild/darwin-x64": "0.20.2",
- "@esbuild/freebsd-arm64": "0.20.2",
- "@esbuild/freebsd-x64": "0.20.2",
- "@esbuild/linux-arm": "0.20.2",
- "@esbuild/linux-arm64": "0.20.2",
- "@esbuild/linux-ia32": "0.20.2",
- "@esbuild/linux-loong64": "0.20.2",
- "@esbuild/linux-mips64el": "0.20.2",
- "@esbuild/linux-ppc64": "0.20.2",
- "@esbuild/linux-riscv64": "0.20.2",
- "@esbuild/linux-s390x": "0.20.2",
- "@esbuild/linux-x64": "0.20.2",
- "@esbuild/netbsd-x64": "0.20.2",
- "@esbuild/openbsd-x64": "0.20.2",
- "@esbuild/sunos-x64": "0.20.2",
- "@esbuild/win32-arm64": "0.20.2",
- "@esbuild/win32-ia32": "0.20.2",
- "@esbuild/win32-x64": "0.20.2"
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/escalade": {
@@ -3275,10 +3302,11 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
- "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@@ -3319,6 +3347,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -3468,10 +3497,11 @@
}
},
"node_modules/picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
- "dev": true
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -3485,9 +3515,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.38",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
- "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"dev": true,
"funding": [
{
@@ -3503,10 +3533,11 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.2.0"
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -3656,37 +3687,17 @@
}
},
"node_modules/rollup": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz",
- "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==",
- "dev": true,
- "dependencies": {
- "@types/estree": "1.0.5"
- },
+ "version": "2.79.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
+ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
+ "license": "MIT",
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
- "node": ">=18.0.0",
- "npm": ">=8.0.0"
+ "node": ">=10.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.18.0",
- "@rollup/rollup-android-arm64": "4.18.0",
- "@rollup/rollup-darwin-arm64": "4.18.0",
- "@rollup/rollup-darwin-x64": "4.18.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.18.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.18.0",
- "@rollup/rollup-linux-arm64-gnu": "4.18.0",
- "@rollup/rollup-linux-arm64-musl": "4.18.0",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.18.0",
- "@rollup/rollup-linux-s390x-gnu": "4.18.0",
- "@rollup/rollup-linux-x64-gnu": "4.18.0",
- "@rollup/rollup-linux-x64-musl": "4.18.0",
- "@rollup/rollup-win32-arm64-msvc": "4.18.0",
- "@rollup/rollup-win32-ia32-msvc": "4.18.0",
- "@rollup/rollup-win32-x64-msvc": "4.18.0",
"fsevents": "~2.3.2"
}
},
@@ -3793,10 +3804,11 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
- "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
@@ -4020,14 +4032,15 @@
"dev": true
},
"node_modules/vite": {
- "version": "5.2.12",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz",
- "integrity": "sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==",
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+ "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "esbuild": "^0.20.1",
- "postcss": "^8.4.38",
- "rollup": "^4.13.0"
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
@@ -4046,6 +4059,7 @@
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
+ "sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
@@ -4063,6 +4077,9 @@
"sass": {
"optional": true
},
+ "sass-embedded": {
+ "optional": true
+ },
"stylus": {
"optional": true
},
@@ -4074,6 +4091,42 @@
}
}
},
+ "node_modules/vite/node_modules/rollup": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz",
+ "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.22.5",
+ "@rollup/rollup-android-arm64": "4.22.5",
+ "@rollup/rollup-darwin-arm64": "4.22.5",
+ "@rollup/rollup-darwin-x64": "4.22.5",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.22.5",
+ "@rollup/rollup-linux-arm-musleabihf": "4.22.5",
+ "@rollup/rollup-linux-arm64-gnu": "4.22.5",
+ "@rollup/rollup-linux-arm64-musl": "4.22.5",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5",
+ "@rollup/rollup-linux-riscv64-gnu": "4.22.5",
+ "@rollup/rollup-linux-s390x-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-musl": "4.22.5",
+ "@rollup/rollup-win32-arm64-msvc": "4.22.5",
+ "@rollup/rollup-win32-ia32-msvc": "4.22.5",
+ "@rollup/rollup-win32-x64-msvc": "4.22.5",
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -4396,163 +4449,163 @@
}
},
"@esbuild/aix-ppc64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
- "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"dev": true,
"optional": true
},
"@esbuild/android-arm": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
- "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"dev": true,
"optional": true
},
"@esbuild/android-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
- "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"dev": true,
"optional": true
},
"@esbuild/android-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
- "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
- "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
- "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
- "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
- "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
- "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
- "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
- "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
- "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
- "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
- "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
- "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
- "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"dev": true,
"optional": true
},
"@esbuild/linux-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
- "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
- "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
- "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
- "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
- "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
- "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"dev": true,
"optional": true
},
"@esbuild/win32-x64": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
- "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"dev": true,
"optional": true
},
@@ -4766,114 +4819,114 @@
}
},
"@rollup/rollup-android-arm-eabi": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
- "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz",
+ "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==",
"dev": true,
"optional": true
},
"@rollup/rollup-android-arm64": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz",
- "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz",
+ "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-darwin-arm64": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz",
- "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz",
+ "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==",
"dev": true,
"optional": true
},
"@rollup/rollup-darwin-x64": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz",
- "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz",
+ "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz",
- "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz",
+ "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz",
- "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz",
+ "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz",
- "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz",
+ "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-musl": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz",
- "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz",
+ "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz",
- "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz",
+ "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz",
- "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz",
+ "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-s390x-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz",
- "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz",
+ "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-gnu": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz",
- "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz",
+ "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==",
"dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-musl": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz",
- "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz",
+ "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-arm64-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz",
- "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz",
+ "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-ia32-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz",
- "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz",
+ "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==",
"dev": true,
"optional": true
},
"@rollup/rollup-win32-x64-msvc": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz",
- "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz",
+ "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==",
"dev": true,
"optional": true
},
@@ -5121,14 +5174,6 @@
"@esbuild/win32-x64": "0.18.20"
}
},
- "rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
- "requires": {
- "fsevents": "~2.3.2"
- }
- },
"rollup-plugin-node-externals": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-externals/-/rollup-plugin-node-externals-4.1.1.tgz",
@@ -5189,9 +5234,9 @@
}
},
"@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.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
},
"@types/node": {
"version": "20.14.0",
@@ -5589,34 +5634,34 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"esbuild": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
- "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true,
"requires": {
- "@esbuild/aix-ppc64": "0.20.2",
- "@esbuild/android-arm": "0.20.2",
- "@esbuild/android-arm64": "0.20.2",
- "@esbuild/android-x64": "0.20.2",
- "@esbuild/darwin-arm64": "0.20.2",
- "@esbuild/darwin-x64": "0.20.2",
- "@esbuild/freebsd-arm64": "0.20.2",
- "@esbuild/freebsd-x64": "0.20.2",
- "@esbuild/linux-arm": "0.20.2",
- "@esbuild/linux-arm64": "0.20.2",
- "@esbuild/linux-ia32": "0.20.2",
- "@esbuild/linux-loong64": "0.20.2",
- "@esbuild/linux-mips64el": "0.20.2",
- "@esbuild/linux-ppc64": "0.20.2",
- "@esbuild/linux-riscv64": "0.20.2",
- "@esbuild/linux-s390x": "0.20.2",
- "@esbuild/linux-x64": "0.20.2",
- "@esbuild/netbsd-x64": "0.20.2",
- "@esbuild/openbsd-x64": "0.20.2",
- "@esbuild/sunos-x64": "0.20.2",
- "@esbuild/win32-arm64": "0.20.2",
- "@esbuild/win32-ia32": "0.20.2",
- "@esbuild/win32-x64": "0.20.2"
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
}
},
"escalade": {
@@ -6267,9 +6312,9 @@
"dev": true
},
"micromatch": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
- "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"requires": {
"braces": "^3.0.3",
@@ -6405,9 +6450,9 @@
"dev": true
},
"picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
"dev": true
},
"picomatch": {
@@ -6416,14 +6461,14 @@
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"postcss": {
- "version": "8.4.38",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
- "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"dev": true,
"requires": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.2.0"
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
}
},
"prelude-ls": {
@@ -6515,28 +6560,10 @@
}
},
"rollup": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz",
- "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==",
- "dev": true,
+ "version": "2.79.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
+ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"requires": {
- "@rollup/rollup-android-arm-eabi": "4.18.0",
- "@rollup/rollup-android-arm64": "4.18.0",
- "@rollup/rollup-darwin-arm64": "4.18.0",
- "@rollup/rollup-darwin-x64": "4.18.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.18.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.18.0",
- "@rollup/rollup-linux-arm64-gnu": "4.18.0",
- "@rollup/rollup-linux-arm64-musl": "4.18.0",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.18.0",
- "@rollup/rollup-linux-s390x-gnu": "4.18.0",
- "@rollup/rollup-linux-x64-gnu": "4.18.0",
- "@rollup/rollup-linux-x64-musl": "4.18.0",
- "@rollup/rollup-win32-arm64-msvc": "4.18.0",
- "@rollup/rollup-win32-ia32-msvc": "4.18.0",
- "@rollup/rollup-win32-x64-msvc": "4.18.0",
- "@types/estree": "1.0.5",
"fsevents": "~2.3.2"
}
},
@@ -6600,9 +6627,9 @@
"dev": true
},
"source-map-js": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
- "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true
},
"sourcemap-codec": {
@@ -6757,15 +6784,43 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"vite": {
- "version": "5.2.12",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz",
- "integrity": "sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==",
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+ "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"dev": true,
"requires": {
- "esbuild": "^0.20.1",
+ "esbuild": "^0.21.3",
"fsevents": "~2.3.3",
- "postcss": "^8.4.38",
- "rollup": "^4.13.0"
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "dependencies": {
+ "rollup": {
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz",
+ "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==",
+ "dev": true,
+ "requires": {
+ "@rollup/rollup-android-arm-eabi": "4.22.5",
+ "@rollup/rollup-android-arm64": "4.22.5",
+ "@rollup/rollup-darwin-arm64": "4.22.5",
+ "@rollup/rollup-darwin-x64": "4.22.5",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.22.5",
+ "@rollup/rollup-linux-arm-musleabihf": "4.22.5",
+ "@rollup/rollup-linux-arm64-gnu": "4.22.5",
+ "@rollup/rollup-linux-arm64-musl": "4.22.5",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5",
+ "@rollup/rollup-linux-riscv64-gnu": "4.22.5",
+ "@rollup/rollup-linux-s390x-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-musl": "4.22.5",
+ "@rollup/rollup-win32-arm64-msvc": "4.22.5",
+ "@rollup/rollup-win32-ia32-msvc": "4.22.5",
+ "@rollup/rollup-win32-x64-msvc": "4.22.5",
+ "@types/estree": "1.0.6",
+ "fsevents": "~2.3.2"
+ }
+ }
}
},
"which": {
diff --git a/frontend/packages/ui/package-lock.json b/frontend/packages/ui/package-lock.json
index f5b7e774b4..0835265f14 100644
--- a/frontend/packages/ui/package-lock.json
+++ b/frontend/packages/ui/package-lock.json
@@ -2984,208 +2984,224 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz",
- "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz",
+ "integrity": "sha512-SU5cvamg0Eyu/F+kLeMXS7GoahL+OoizlclVFX3l5Ql6yNlywJJ0OuqTzUx0v+aHhPHEB/56CT06GQrRrGNYww==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz",
- "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.5.tgz",
+ "integrity": "sha512-S4pit5BP6E5R5C8S6tgU/drvgjtYW76FBuG6+ibG3tMvlD1h9LHVF9KmlmaUBQ8Obou7hEyS+0w+IR/VtxwNMQ==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz",
- "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.5.tgz",
+ "integrity": "sha512-250ZGg4ipTL0TGvLlfACkIxS9+KLtIbn7BCZjsZj88zSg2Lvu3Xdw6dhAhfe/FjjXPVNCtcSp+WZjVsD3a/Zlw==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz",
- "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.5.tgz",
+ "integrity": "sha512-D8brJEFg5D+QxFcW6jYANu+Rr9SlKtTenmsX5hOSzNYVrK5oLAEMTUgKWYJP+wdKyCdeSwnapLsn+OVRFycuQg==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz",
- "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.5.tgz",
+ "integrity": "sha512-PNqXYmdNFyWNg0ma5LdY8wP+eQfdvyaBAojAXgO7/gs0Q/6TQJVXAXe8gwW9URjbS0YAammur0fynYGiWsKlXw==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz",
- "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.5.tgz",
+ "integrity": "sha512-kSSCZOKz3HqlrEuwKd9TYv7vxPYD77vHSUvM2y0YaTGnFc8AdI5TTQRrM1yIp3tXCKrSL9A7JLoILjtad5t8pQ==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz",
- "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.5.tgz",
+ "integrity": "sha512-oTXQeJHRbOnwRnRffb6bmqmUugz0glXaPyspp4gbQOPVApdpRrY/j7KP3lr7M8kTfQTyrBUzFjj5EuHAhqH4/w==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz",
- "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.5.tgz",
+ "integrity": "sha512-qnOTIIs6tIGFKCHdhYitgC2XQ2X25InIbZFor5wh+mALH84qnFHvc+vmWUpyX97B0hNvwNUL4B+MB8vJvH65Fw==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz",
- "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.5.tgz",
+ "integrity": "sha512-TMYu+DUdNlgBXING13rHSfUc3Ky5nLPbWs4bFnT+R6Vu3OvXkTkixvvBKk8uO4MT5Ab6lC3U7x8S8El2q5o56w==",
"cpu": [
"ppc64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz",
- "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.5.tgz",
+ "integrity": "sha512-PTQq1Kz22ZRvuhr3uURH+U/Q/a0pbxJoICGSprNLAoBEkyD3Sh9qP5I0Asn0y0wejXQBbsVMRZRxlbGFD9OK4A==",
"cpu": [
"riscv64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz",
- "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.5.tgz",
+ "integrity": "sha512-bR5nCojtpuMss6TDEmf/jnBnzlo+6n1UhgwqUvRoe4VIotC7FG1IKkyJbwsT7JDsF2jxR+NTnuOwiGv0hLyDoQ==",
"cpu": [
"s390x"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz",
- "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.5.tgz",
+ "integrity": "sha512-N0jPPhHjGShcB9/XXZQWuWBKZQnC1F36Ce3sDqWpujsGjDz/CQtOL9LgTrJ+rJC8MJeesMWrMWVLKKNR/tMOCA==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz",
- "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.5.tgz",
+ "integrity": "sha512-uBa2e28ohzNNwjr6Uxm4XyaA1M/8aTgfF2T7UIlElLaeXkgpmIJ2EitVNQxjO9xLLLy60YqAgKn/AqSpCUkE9g==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz",
- "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.5.tgz",
+ "integrity": "sha512-RXT8S1HP8AFN/Kr3tg4fuYrNxZ/pZf1HemC5Tsddc6HzgGnJm0+Lh5rAHJkDuW3StI0ynNXukidROMXYl6ew8w==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz",
- "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.5.tgz",
+ "integrity": "sha512-ElTYOh50InL8kzyUD6XsnPit7jYCKrphmddKAe1/Ytt74apOxDq5YEcbsiKs0fR3vff3jEneMM+3I7jbqaMyBg==",
"cpu": [
"ia32"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz",
- "integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.5.tgz",
+ "integrity": "sha512-+lvL/4mQxSV8MukpkKyyvfwhH266COcWlXE/1qxwN08ajovta3459zrjLghYMgDerlzNwLAcFpvU+WWE5y6nAQ==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -4295,10 +4311,11 @@
"dev": true
},
"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==",
- "dev": true
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/express": {
"version": "4.17.21",
@@ -5148,9 +5165,9 @@
}
},
"node_modules/body-parser": {
- "version": "1.20.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
- "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5162,7 +5179,7 @@
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
- "qs": "6.11.0",
+ "qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
@@ -5923,9 +5940,9 @@
"dev": true
},
"node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -6555,38 +6572,38 @@
}
},
"node_modules/express": {
- "version": "4.19.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
- "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz",
+ "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==",
"dev": true,
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.20.2",
+ "body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "1.2.0",
+ "finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
- "merge-descriptors": "1.0.1",
+ "merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
+ "path-to-regexp": "0.1.10",
"proxy-addr": "~2.0.7",
- "qs": "6.11.0",
+ "qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
- "send": "0.18.0",
- "serve-static": "1.15.0",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
@@ -6712,14 +6729,14 @@
}
},
"node_modules/finalhandler": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
- "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
@@ -8144,11 +8161,14 @@
}
},
"node_modules/merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
"node_modules/merge-stream": {
"version": "2.0.0",
@@ -8176,10 +8196,11 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
- "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@@ -8933,9 +8954,9 @@
}
},
"node_modules/path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
+ "version": "0.1.10",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
+ "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
"dev": true,
"license": "MIT"
},
@@ -8965,10 +8986,11 @@
}
},
"node_modules/picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
- "dev": true
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -9104,9 +9126,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.39",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
- "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"dev": true,
"funding": [
{
@@ -9122,10 +9144,11 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.1",
- "source-map-js": "^1.2.0"
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -9369,13 +9392,13 @@
}
},
"node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
- "side-channel": "^1.0.4"
+ "side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -9835,12 +9858,13 @@
}
},
"node_modules/rollup": {
- "version": "4.18.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz",
- "integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==",
+ "version": "4.22.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz",
+ "integrity": "sha512-WoinX7GeQOFMGznEcWA1WrTQCd/tpEbMkc3nuMs9BT0CPjMdSjPMTVClwWd4pgSQwJdP65SK9mTCNvItlr5o7w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@types/estree": "1.0.5"
+ "@types/estree": "1.0.6"
},
"bin": {
"rollup": "dist/bin/rollup"
@@ -9850,22 +9874,22 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.18.1",
- "@rollup/rollup-android-arm64": "4.18.1",
- "@rollup/rollup-darwin-arm64": "4.18.1",
- "@rollup/rollup-darwin-x64": "4.18.1",
- "@rollup/rollup-linux-arm-gnueabihf": "4.18.1",
- "@rollup/rollup-linux-arm-musleabihf": "4.18.1",
- "@rollup/rollup-linux-arm64-gnu": "4.18.1",
- "@rollup/rollup-linux-arm64-musl": "4.18.1",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.18.1",
- "@rollup/rollup-linux-riscv64-gnu": "4.18.1",
- "@rollup/rollup-linux-s390x-gnu": "4.18.1",
- "@rollup/rollup-linux-x64-gnu": "4.18.1",
- "@rollup/rollup-linux-x64-musl": "4.18.1",
- "@rollup/rollup-win32-arm64-msvc": "4.18.1",
- "@rollup/rollup-win32-ia32-msvc": "4.18.1",
- "@rollup/rollup-win32-x64-msvc": "4.18.1",
+ "@rollup/rollup-android-arm-eabi": "4.22.5",
+ "@rollup/rollup-android-arm64": "4.22.5",
+ "@rollup/rollup-darwin-arm64": "4.22.5",
+ "@rollup/rollup-darwin-x64": "4.22.5",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.22.5",
+ "@rollup/rollup-linux-arm-musleabihf": "4.22.5",
+ "@rollup/rollup-linux-arm64-gnu": "4.22.5",
+ "@rollup/rollup-linux-arm64-musl": "4.22.5",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.22.5",
+ "@rollup/rollup-linux-riscv64-gnu": "4.22.5",
+ "@rollup/rollup-linux-s390x-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-gnu": "4.22.5",
+ "@rollup/rollup-linux-x64-musl": "4.22.5",
+ "@rollup/rollup-win32-arm64-msvc": "4.22.5",
+ "@rollup/rollup-win32-ia32-msvc": "4.22.5",
+ "@rollup/rollup-win32-x64-msvc": "4.22.5",
"fsevents": "~2.3.2"
}
},
@@ -9940,9 +9964,9 @@
}
},
"node_modules/send": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
- "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9981,6 +10005,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/send/node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -9989,16 +10023,16 @@
"license": "MIT"
},
"node_modules/serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "encodeurl": "~1.0.2",
+ "encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
- "send": "0.18.0"
+ "send": "0.19.0"
},
"engines": {
"node": ">= 0.8.0"
@@ -10113,10 +10147,11 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
- "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
@@ -11124,14 +11159,15 @@
}
},
"node_modules/vite": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz",
- "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==",
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+ "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
- "postcss": "^8.4.39",
- "rollup": "^4.13.0"
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
@@ -11150,6 +11186,7 @@
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
+ "sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
@@ -11167,6 +11204,9 @@
"sass": {
"optional": true
},
+ "sass-embedded": {
+ "optional": true
+ },
"stylus": {
"optional": true
},
diff --git a/helm/Chart.yaml b/helm/Chart.yaml
index 3cf60f1250..7df587e17e 100644
--- a/helm/Chart.yaml
+++ b/helm/Chart.yaml
@@ -14,16 +14,16 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 2.7.1
+version: 2.8.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
-appVersion: "0.16.2"
+appVersion: "1.0.0-dev0"
dependencies:
- name: neo4j
- version: "5.19.0"
+ version: "5.20.0"
repository: "https://helm.neo4j.com/neo4j/"
condition: neo4j.enabled
- name: common
@@ -50,3 +50,7 @@ dependencies:
version: "28.2.0"
repository: "https://traefik.github.io/charts"
condition: traefik.enabled
+ - name: prefect-server
+ version: "2024.7.25191224"
+ repository: "https://prefecthq.github.io/prefect-helm"
+ condition: prefect-server.enabled
diff --git a/helm/templates/_env.tpl b/helm/templates/_env.tpl
index c33bf831fe..a4abb50dd7 100644
--- a/helm/templates/_env.tpl
+++ b/helm/templates/_env.tpl
@@ -129,3 +129,46 @@ Define default env variables if required.
value: "{{ .Values.redis.master.service.ports.redis }}"
{{- end }}
{{- end }}
+
+{{- define "infrahub-helm.infrahubTaskRunner.defaultEnv" -}}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.KUBERNETES_CLUSTER_DOMAIN }}
+- name: KUBERNETES_CLUSTER_DOMAIN
+ value: {{ quote .Values.global.kubernetesClusterDomain }}
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_ADDRESS }}
+- name: INFRAHUB_ADDRESS
+ value: http://{{ include "infrahub-helm.fullname" . }}-infrahub-server.{{ .Release.Namespace }}.svc.{{ .Values.global.kubernetesClusterDomain }}:8000
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_INTERNAL_ADDRESS }}
+- name: INFRAHUB_INTERNAL_ADDRESS
+ value: "http://{{ include "infrahub-helm.fullname" . }}-infrahub-server.{{ .Release.Namespace }}.svc.{{ .Values.global.kubernetesClusterDomain }}:8000"
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_DB_ADDRESS }}
+- name: INFRAHUB_DB_ADDRESS
+ value: "{{ include "infrahub-helm.fullname" . }}-database.{{ .Release.Namespace }}.svc.{{ .Values.global.kubernetesClusterDomain }}"
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_DB_PORT }}
+- name: INFRAHUB_DB_PORT
+ value: "{{ .Values.neo4j.services.neo4j.ports.bolt.port }}"
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_BROKER_ADDRESS }}
+- name: INFRAHUB_BROKER_ADDRESS
+ value: "{{ include "infrahub-helm.fullname" . }}-message-queue.{{ .Release.Namespace }}.svc.{{ .Values.global.kubernetesClusterDomain }}"
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_BROKER_USERNAME }}
+- name: INFRAHUB_BROKER_USERNAME
+ value: {{ .Values.rabbitmq.auth.username | quote }}
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_BROKER_PASSWORD }}
+- name: INFRAHUB_BROKER_PASSWORD
+ value: {{ .Values.rabbitmq.auth.password | quote }}
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_CACHE_ADDRESS }}
+- name: INFRAHUB_CACHE_ADDRESS
+ value: "{{ include "infrahub-helm.fullname" . }}-cache-master.{{ .Release.Namespace }}.svc.{{ .Values.global.kubernetesClusterDomain }}"
+{{- end }}
+{{- if not .Values.infrahubTaskRunner.infrahubTaskRunner.env.INFRAHUB_CACHE_PORT }}
+- name: INFRAHUB_CACHE_PORT
+ value: "{{ .Values.redis.master.service.ports.redis }}"
+{{- end }}
+{{- end }}
diff --git a/helm/templates/infrahub-demo-data-job.yaml b/helm/templates/infrahub-demo-data-job.yaml
index eb940e45c1..e5c6cc8921 100644
--- a/helm/templates/infrahub-demo-data-job.yaml
+++ b/helm/templates/infrahub-demo-data-job.yaml
@@ -15,9 +15,7 @@ spec:
spec:
containers:
- command:
- - sh
- - -c
- - "infrahubctl schema load models/base --wait 30 || infrahubctl schema load models/infrastructure_base.yml && infrahubctl run models/infrastructure_edge.py && infrahubctl repository add demo-edge https://github.com/opsmill/infrahub-demo-edge --read-only"
+ {{- toYaml .Values.infrahubDemoData.command | nindent 12 }}
env:
{{- include "infrahub-helm.infrahubDemoData.defaultEnv" . | nindent 12 }}
{{- with .Values.infrahubDemoData.env }}
diff --git a/helm/templates/infrahub-git.yaml b/helm/templates/infrahub-git.yaml
index 8faff1c918..fc7d904b3a 100644
--- a/helm/templates/infrahub-git.yaml
+++ b/helm/templates/infrahub-git.yaml
@@ -19,7 +19,14 @@ spec:
metadata:
labels:
service: infrahub-git
+ {{- with .Values.infrahubGit.podLabels }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
{{- include "infrahub-helm.selectorLabels" . | nindent 8 }}
+ {{- with .Values.infrahubGit.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
spec:
{{- with .Values.infrahubGit.affinity }}
affinity: {{- toYaml . | nindent 8 }}
diff --git a/helm/templates/infrahub-server.yaml b/helm/templates/infrahub-server.yaml
index d4bbe2ee2e..ff0dd50e37 100644
--- a/helm/templates/infrahub-server.yaml
+++ b/helm/templates/infrahub-server.yaml
@@ -19,7 +19,14 @@ spec:
metadata:
labels:
service: infrahub-server
+ {{- with .Values.infrahubServer.podLabels }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
{{- include "infrahub-helm.selectorLabels" . | nindent 8 }}
+ {{- with .Values.infrahubServer.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
spec:
{{- with .Values.infrahubServer.affinity }}
affinity: {{- toYaml . | nindent 8 }}
@@ -77,6 +84,8 @@ spec:
volumeMounts:
- mountPath: /opt/infrahub/storage
name: infrahub-server-storage-data
+ - name: workflow-data
+ mountPath: /opt/infrahub/workflow
restartPolicy: Always
volumes:
{{- if and .Values.infrahubServer.persistence.enabled }}
@@ -87,6 +96,14 @@ spec:
- name: infrahub-server-storage-data
emptyDir: {}
{{- end }}
+ {{- if and .Values.infrahubTaskRunner.persistence.enabled }}
+ - name: workflow-data
+ persistentVolumeClaim:
+ claimName: {{ tpl (.Values.infrahubTaskRunner.persistence.existingClaim | default (printf "%s-%s" (include "infrahub-helm.fullname" .) "workflow-data")) . }}
+ {{- else }}
+ - name: workflow-data
+ emptyDir: {}
+ {{- end }}
---
apiVersion: v1
diff --git a/helm/templates/infrahub-task-runner.yaml b/helm/templates/infrahub-task-runner.yaml
new file mode 100644
index 0000000000..c17ffe01ab
--- /dev/null
+++ b/helm/templates/infrahub-task-runner.yaml
@@ -0,0 +1,97 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "infrahub-helm.fullname" . }}-infrahub-task-runner
+ labels:
+ service: infrahub-task-runner
+ {{- include "infrahub-helm.labels" . | nindent 4 }}
+spec:
+ replicas: {{ .Values.infrahubTaskRunner.replicas | default 1 }}
+ selector:
+ matchLabels:
+ service: infrahub-task-runner
+ {{- include "infrahub-helm.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ labels:
+ service: infrahub-task-runner
+ {{- with .Values.infrahubTaskRunner.podLabels }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- include "infrahub-helm.selectorLabels" . | nindent 8 }}
+ {{- with .Values.infrahubTaskRunner.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ spec:
+ {{- with .Values.infrahubTaskRunner.affinity }}
+ affinity: {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.infrahubTaskRunner.tolerations }}
+ tolerations: {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.infrahubTaskRunner.runtimeClassName }}
+ runtimeClassName: {{ . }}
+ {{- end }}
+ containers:
+ - args: {{- toYaml .Values.infrahubTaskRunner.infrahubTaskRunner.args | nindent 12 }}
+ env:
+ {{- include "infrahub-helm.infrahubTaskRunner.defaultEnv" . | nindent 12 }}
+ {{- range $key, $value := .Values.infrahubTaskRunner.infrahubTaskRunner.env }}
+ - name: {{ $key }}
+ value: {{ $value | quote }}
+ {{- end }}
+ {{- with .Values.infrahubTaskRunner.infrahubTaskRunner.envFromExistingSecret }}
+ envFrom:
+ - secretRef:
+ name: {{ . }}
+ {{- end }}
+ image: {{ default .Values.global.imageRegistry .Values.infrahubTaskRunner.infrahubTaskRunner.imageRegistry }}/{{ .Values.global.infrahubRepository }}:{{ .Values.global.infrahubTag | default .Chart.AppVersion }}
+ imagePullPolicy: {{ default .Values.global.imagePullPolicy .Values.infrahubTaskRunner.infrahubTaskRunner.imagePullPolicy }}
+ name: infrahub-task-runner
+ resources: {}
+ tty: true
+ volumeMounts:
+ - name: git-data
+ mountPath: /opt/infrahub/git
+ - name: workflow-data
+ mountPath: /opt/infrahub/workflow
+ restartPolicy: Always
+ volumes:
+ {{- if and .Values.infrahubGit.persistence.enabled }}
+ - name: git-data
+ persistentVolumeClaim:
+ claimName: {{ tpl (.Values.infrahubGit.persistence.existingClaim | default (printf "%s-%s" (include "infrahub-helm.fullname" .) "git-data")) . }}
+ {{- else }}
+ - name: git-data
+ emptyDir: {}
+ {{- end }}
+ {{- if and .Values.infrahubTaskRunner.persistence.enabled }}
+ - name: workflow-data
+ persistentVolumeClaim:
+ claimName: {{ tpl (.Values.infrahubTaskRunner.persistence.existingClaim | default (printf "%s-%s" (include "infrahub-helm.fullname" .) "workflow-data")) . }}
+ {{- else }}
+ - name: workflow-data
+ emptyDir: {}
+ {{- end }}
+
+{{- if and .Values.infrahubTaskRunner.persistence.enabled (not .Values.infrahubTaskRunner.persistence.existingClaim) }}
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: {{ include "infrahub-helm.fullname" . }}-workflow-data
+ labels:
+ service: workflow-data
+ {{- include "infrahub-helm.labels" . | nindent 4 }}
+spec:
+ accessModes:
+ - {{ .Values.infrahubTaskRunner.persistence.accessMode }}
+ resources:
+ requests:
+ storage: {{ .Values.infrahubTaskRunner.persistence.size | quote }}
+ {{- with .Values.infrahubTaskRunner.persistence.storageClassName }}
+ storageClassName: {{ . }}
+ {{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/helm/values.yaml b/helm/values.yaml
index 4851144d9c..6e2fd0efc1 100644
--- a/helm/values.yaml
+++ b/helm/values.yaml
@@ -1,3 +1,4 @@
+# yamllint disable rule:line-length
---
global:
kubernetesClusterDomain: cluster.local
@@ -75,6 +76,45 @@ infrahubGit:
INFRAHUB_API_TOKEN: 06438eb2-8019-4776-878c-0941b1f1d1ec
INFRAHUB_TIMEOUT: "20"
INFRAHUB_GIT_REPOSITORIES_DIRECTORY: "/opt/infrahub/git"
+ PREFECT_API_URL: "http://prefect-server:4200/api"
+ PREFECT_WORKER_QUERY_SECONDS: 3
+ PREFECT_AGENT_QUERY_INTERVAL: 3
+ PREFECT_LOCAL_STORAGE_PATH: /opt/infrahub/workflow
+ imagePullPolicy: Always
+ imageRegistry: registry.opsmill.io
+
+# ----------- Infrahub Task Runner -----------
+infrahubTaskRunner:
+ replicas: 2
+ persistence:
+ enabled: true
+ size: 100Mi
+ accessMode: ReadWriteMany
+ storageClassName: nfs
+ infrahubTaskRunner:
+ args:
+ - prefect
+ - worker
+ - start
+ - --type
+ - infrahubasync
+ - --pool
+ - infrahub-worker
+ - --with-healthcheck
+ env:
+ INFRAHUB_CACHE_PORT: 6379
+ INFRAHUB_DB_TYPE: neo4j
+ INFRAHUB_LOG_LEVEL: DEBUG
+ INFRAHUB_PRODUCTION: "false"
+ INFRAHUB_API_TOKEN: 06438eb2-8019-4776-878c-0941b1f1d1ec
+ INFRAHUB_TIMEOUT: "20"
+ INFRAHUB_GIT_REPOSITORIES_DIRECTORY: "/opt/infrahub/git"
+ INFRAHUB_WORKFLOW_ADDRESS: prefect-server
+ INFRAHUB_WORKFLOW_PORT: 4200
+ PREFECT_API_URL: "http://prefect-server:4200/api"
+ PREFECT_WORKER_QUERY_SECONDS: 3
+ PREFECT_AGENT_QUERY_INTERVAL: 3
+ PREFECT_LOCAL_STORAGE_PATH: /opt/infrahub/workflow
imagePullPolicy: Always
imageRegistry: registry.opsmill.io
@@ -110,6 +150,10 @@ infrahubServer:
INFRAHUB_INITIAL_ADMIN_TOKEN: 06438eb2-8019-4776-878c-0941b1f1d1ec
INFRAHUB_SECURITY_SECRET_KEY: 327f747f-efac-42be-9e73-999f08f86b92
INFRAHUB_GIT_REPOSITORIES_DIRECTORY: "/opt/infrahub/git"
+ INFRAHUB_WORKFLOW_ADDRESS: prefect-server
+ INFRAHUB_WORKFLOW_PORT: 4200
+ PREFECT_API_URL: "http://prefect-server:4200/api"
+ PREFECT_LOCAL_STORAGE_PATH: /opt/infrahub/workflow
imagePullPolicy: Always
imageRegistry: registry.opsmill.io
ports:
@@ -136,6 +180,10 @@ infrahubDemoData:
imageRegistry: registry.opsmill.io
env:
INFRAHUB_API_TOKEN: 06438eb2-8019-4776-878c-0941b1f1d1ec
+ command:
+ - sh
+ - -c
+ - "infrahubctl schema load models/base --wait 30 && infrahubctl run models/infrastructure_edge.py && infrahubctl repository add demo-edge https://github.com/opsmill/infrahub-demo-edge --read-only"
# ----------- Mesage Queue (Rabbit MQ) -----------
rabbitmq:
@@ -166,6 +214,23 @@ nats:
jetstream:
enabled: true
+# ------------- Prefect -------------
+prefect-server:
+ enabled: true
+ server:
+ image:
+ prefectTag: 3.0.3-python3.12-kubernetes
+ env:
+ - name: PREFECT_UI_SERVE_BASE
+ value: /
+ serviceAccount:
+ create: false
+ postgresql:
+ enabled: true
+ primary:
+ persistence:
+ enabled: false
+
# -------------- Cloud --------------
traefik:
enabled: false
diff --git a/models/examples/security/infrastructure_security.py b/models/examples/security/infrastructure_security.py
index 06a56b04bf..36ca232076 100644
--- a/models/examples/security/infrastructure_security.py
+++ b/models/examples/security/infrastructure_security.py
@@ -4,6 +4,8 @@
from infrahub_sdk import InfrahubClient, InfrahubNode, NodeStore
+from infrahub_sdk.protocols import CoreAccount
+
# flake8: noqa
# pylint: skip-file
@@ -179,8 +181,7 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str):
async for node, _ in batch.execute():
prepare_log(node, log)
- account_security = store.get("security-builder")
- store.get("John Doe")
+ account_security = store.get(key="security-builder", kind=CoreAccount, raise_when_missing=True)
# ------------------------------------------
# Create Status, Role & Tags
diff --git a/models/infrastructure_edge.py b/models/infrastructure_edge.py
index 35d44de1c1..2637836795 100644
--- a/models/infrastructure_edge.py
+++ b/models/infrastructure_edge.py
@@ -1,13 +1,137 @@
+import copy
import logging
+import time
import uuid
from collections import defaultdict
+from enum import Enum
from ipaddress import IPv4Network, IPv6Network
-from typing import Optional
+from typing import Optional, cast
-from infrahub_sdk import UUIDT, InfrahubClient, InfrahubNode, NodeStore
+from infrahub_sdk import UUIDT, InfrahubClient, NodeStore
from infrahub_sdk.batch import InfrahubBatch
+from infrahub_sdk.protocols import (
+ CoreAccount,
+ CoreAccountGroup,
+ CoreIPAddressPool,
+ CoreIPPrefixPool,
+ CoreStandardGroup,
+ IpamNamespace,
+)
+from infrahub_sdk.protocols_base import CoreNode
+from protocols import (
+ InfraAutonomousSystem,
+ InfraBGPSession,
+ InfraCircuit,
+ InfraCircuitEndpoint,
+ InfraDevice,
+ InfraInterfaceL2,
+ InfraInterfaceL3,
+ InfraLagInterfaceL2,
+ InfraMlagDomain,
+ InfraMlagInterfaceL2,
+ InfraPlatform,
+ InfraVLAN,
+ IpamIPAddress,
+ IpamIPPrefix,
+ LocationCountry,
+ LocationSite,
+ OrganizationProvider,
+)
from pydantic import BaseModel, ConfigDict, Field
+PROFILES = {
+ "small": {"num_sites": 2, "num_device_per_site": 6, "has_bgp_mesh": False, "has_branch": False},
+ "medium": {"num_sites": 5, "num_device_per_site": 6, "has_bgp_mesh": True, "has_branch": True},
+ "large": {"num_sites": 10, "num_device_per_site": 26, "has_bgp_mesh": False, "has_branch": False},
+ "x-large": {"num_sites": 50, "num_device_per_site": 52, "has_bgp_mesh": False, "has_branch": False},
+ "xx-large": {"num_sites": 100, "num_device_per_site": 102, "has_bgp_mesh": False, "has_branch": False},
+ "ultimate": {"num_sites": 200, "num_device_per_site": 204, "has_bgp_mesh": True, "has_branch": True},
+}
+
+
+class ConfigError(Exception):
+ pass
+
+
+# Define the global configuration object
+class GlobalConfig:
+ def __init__(self) -> None:
+ self.default_profile_name = "medium"
+ self.num_sites = None
+ self.num_device_per_site = None
+ self.has_bgp_mesh = False
+ self.has_branch = False
+
+ def __set_config(self, num_sites: int, num_device_per_site: int, has_bgp_mesh: bool, has_branch: bool) -> None:
+ # TODO: I guess it could be defined in the attribute itself?
+ # Ensure that num_site is between boudaries
+ if 2 <= int(num_sites) <= 200:
+ self.num_sites = int(num_sites)
+ else:
+ raise ConfigError(f"Value for `num_sites` ({num_sites}) should be between 2 and 200.")
+
+ # Ensure that num_device_per_site is between boudaries
+ if 6 <= int(num_device_per_site) <= 204:
+ self.num_device_per_site = int(num_device_per_site)
+ else:
+ raise ConfigError(f"Value for `num_device_per_site` ({num_device_per_site}) should be between 6 and 204.")
+
+ self.has_bgp_mesh = has_bgp_mesh
+ self.has_branch = has_branch
+
+ def load_config(
+ self,
+ profile: str = None,
+ num_sites: int = None,
+ num_device_per_site: int = None,
+ has_bgp_mesh: bool = None,
+ has_branch: bool = None,
+ ) -> None:
+ if profile:
+ # Warn user that we are going to ignore his input
+ if num_sites or num_device_per_site or has_bgp_mesh or has_branch:
+ raise ConfigError("You can't set additional config items if you've already provided a profile.")
+
+ # Make sure profile exists
+ if profile not in PROFILES:
+ raise ConfigError(
+ f"Value for profile ({profile}) doesn't exist, please pick one among {PROFILES.keys()}."
+ )
+
+ # Load prebuilt profile
+ profile_obj: dict = PROFILES[profile]
+ self.__set_config(
+ profile_obj["num_sites"],
+ profile_obj["num_device_per_site"],
+ profile_obj["has_bgp_mesh"],
+ profile_obj["has_branch"],
+ )
+ else:
+ # Load from manual arguments, if provided
+ # If user only provides a part of the arguments e.g. only `number of site`
+ # we fall back on medium profile by default
+ default_profile: dict = PROFILES[self.default_profile_name]
+
+ self.__set_config(
+ num_sites=num_sites if num_sites is not None else default_profile["num_sites"],
+ num_device_per_site=num_device_per_site
+ if num_device_per_site is not None
+ else default_profile["num_device_per_site"],
+ has_bgp_mesh=has_bgp_mesh if has_bgp_mesh is not None else default_profile["has_bgp_mesh"],
+ has_branch=has_branch if has_branch is not None else default_profile["has_branch"],
+ )
+
+ def __repr__(self) -> str:
+ return f"Config(Sites: {self.num_sites}, Devices per site: {self.num_device_per_site}, BGP mesh: {self.has_bgp_mesh}, Additional branches: {self.has_branch})"
+
+
+def translate_str_to_bool(key: str, value: str) -> bool:
+ if value == "True":
+ return True
+ if value == "False":
+ return False
+ raise TypeError(f"Value for {key} should be 'True' or 'False'")
+
# pylint: skip-file
class Account(BaseModel):
@@ -42,6 +166,7 @@ class Device(BaseModel):
role: str
tags: list[str]
platform: str
+ _idx: int
@property
def l2_interface_names(self) -> list[str]:
@@ -107,7 +232,7 @@ class P2pNetwork(BaseModel):
site2: str
edge: int
circuit: str
- pool: Optional[InfrahubNode] = None
+ pool: Optional[IpamIPPrefix] = None
model_config = ConfigDict(arbitrary_types_allowed=True)
@@ -129,6 +254,11 @@ def provider_name(self) -> str:
return "Lumen"
return "Zayo"
+ def get_pool(self) -> IpamIPPrefix:
+ if self.pool:
+ return self.pool
+ raise Exception("the variable pool hasn't been initilized yet")
+
class Platform(BaseModel):
name: str
@@ -212,68 +342,120 @@ class Vlan(BaseModel):
),
)
-DEVICES = (
- Device(
- name="edge1",
+
+class DevicePatternName(str, Enum):
+ LEAF = "LEAF"
+ CORE = "CORE"
+ EDGE = "EDGE"
+
+
+DEVICE_PATTERNS = {
+ DevicePatternName.LEAF: Device(
+ name="leaf",
status="active",
- type="7280R3",
+ type="7010TX-48",
profile="profile1",
- role="edge",
+ role="leaf",
tags=["red", "green"],
- platform="Arista EOS",
- ),
- Device(
- name="edge2",
- status="active",
- type="ASR1002-HX",
- profile="profile1",
- role="edge",
- tags=["red", "blue", "green"],
platform="Cisco IOS",
),
- Device(
- name="core1",
- status="drained",
+ DevicePatternName.CORE: Device(
+ name="core",
+ status="active",
type="MX204",
profile="profile1",
role="core",
tags=["blue"],
platform="Juniper JunOS",
),
- Device(
- name="core2",
- status="provisioning",
- type="MX204",
- profile="profile1",
- role="core",
- tags=["red"],
- platform="Juniper JunOS",
- ),
- Device(
- name="leaf1",
- status="active",
- type="7010TX-48",
- profile="profile1",
- role="leaf",
- tags=["red", "green"],
- platform="Arista EOS",
- ),
- Device(
- name="leaf2",
+ DevicePatternName.EDGE: Device(
+ name="edge",
status="active",
- type="7010TX-48",
+ type="7280R3",
profile="profile1",
- role="leaf",
+ role="edge",
tags=["red", "green"],
platform="Arista EOS",
),
-)
+}
+
+DEVICE_STATUSES = ["active", "provisioning", "drained"]
+
+
+class SiteDesign:
+ def __init__(self, number_of_device: int) -> None:
+ """Takes the number of devices that need to be created on a given site.
+ This method will decide how many device of each type to create and return all those objects as a list."""
+ if number_of_device > 0:
+ self.number_of_device = number_of_device
+ else:
+ raise ValueError("number_of_device must be non-negative")
+
+ # There is a special case where there are 6 device...
+ if number_of_device == 6:
+ # Two of each
+ self.num_edge_device = 2
+ self.num_core_device = 2
+ self.num_leaf_device = 2
+
+ # Otherwise we try to compute something that makes a little bit of sense...
+ else:
+ # First we decide how many edge device we will spin
+ # The rule is the following:
+ # - between 0 -> 50 = 2 edges
+ # - then we add 2 edges every 50 devices
+ num_edge_device: int = 2
+ num_edge_device += (self.number_of_device // 50) * 2
+ self.num_edge_device = num_edge_device
+
+ # Second goes core device, we take one third of the remaining device allocation
+ self.num_core_device: int = (self.number_of_device - self.num_edge_device) // 3
+
+ # Finally we allocate what's remaining as leaf
+ self.num_leaf_device: int = self.number_of_device - self.num_edge_device - self.num_core_device
+
+ def device_generator(self, number: int, device_pattern_name: DevicePatternName) -> list[Device]:
+ """Generate a list of devices following the pattern provided."""
+ result: list[Device] = []
+
+ for i in range(1, number + 1):
+ # Take the pattern as baseline
+ current_device: Device = copy.copy(DEVICE_PATTERNS[device_pattern_name])
+
+ # Start the tweaking
+ current_device.name += str(i)
+ current_device._idx = i
+
+ # Add it to the list
+ result.append(current_device)
+
+ # Return devices
+ return result
+
+ def implement(self) -> list[Device]:
+ # Build the list of device
+ result: list[Device] = []
+
+ # Generate the list and return it
+ result.extend(self.device_generator(self.num_edge_device, DevicePatternName.EDGE))
+ result.extend(self.device_generator(self.num_core_device, DevicePatternName.CORE))
+ result.extend(self.device_generator(self.num_leaf_device, DevicePatternName.LEAF))
+
+ return result
+
+ def __repr__(self) -> str:
+ return f"SiteDesign(Edge device: {self.num_edge_device}, Core device: {self.num_core_device}, Leaf device: {self.num_leaf_device})"
NETWORKS_SUPERNET = IPv4Network("10.0.0.0/8")
-NETWORKS_SUPERNET_IPV6 = IPv6Network("2001:DB8::/112")
-NETWORKS_POOL_EXTERNAL_SUPERNET = IPv4Network("203.0.113.0/24")
-MANAGEMENT_NETWORKS = IPv4Network("172.20.20.0/27")
+NETWORKS_SUPERNET_IPV6 = IPv6Network("2001:DB8::/100")
+MANAGEMENT_NETWORKS = IPv4Network("172.16.0.0/16")
+
+# Here with current logic we allocate 3 /29 per edge device
+# We have max 10 edges on a single site, max 200 sites
+# 3*10*200 = 6000 -> we need to be able to fit 6000 /29
+# Thus we need a /16
+NETWORKS_POOL_EXTERNAL_SUPERNET = IPv4Network("203.111.0.0/16")
ACTIVE_STATUS = "active"
BACKBONE_ROLE = "backbone"
@@ -368,7 +550,9 @@ def site_generator(nbr_site: int = 2) -> list[Site]:
],
}
-LAG_INTERFACE_L2_ROLES_MAPPING = {"leaf": {"port-channel1": "peer", "port-channel2": "server"}}
+LAG_INTERFACE_L2_ROLES_MAPPING: dict[str, dict[str, str]] = {
+ "leaf": {"port-channel1": "peer", "port-channel2": "server"}
+}
INTERFACE_L2_MODE_MAPPING = {"peer": "Trunk (ALL)"}
@@ -433,7 +617,7 @@ def site_generator(nbr_site: int = 2) -> list[Site]:
Asn(asn=7018, organization="AT&T Services"),
)
-INTERFACE_OBJS: dict[str, list[InfrahubNode]] = defaultdict(list)
+INTERFACE_OBJS: dict[str, list[InfraInterfaceL3]] = defaultdict(list)
ACCOUNTS = (
Account(name="pop-builder", account_type="Script", password="Password123", role="read-write"),
@@ -510,15 +694,41 @@ def site_generator(nbr_site: int = 2) -> list[Site]:
store = NodeStore()
+async def find_and_connect_interfaces(
+ batch: InfrahubBatch,
+ log: logging.Logger,
+ interface_kind: InfraInterfaceL2 | InfraInterfaceL3,
+ first_device_name: str,
+ first_interface_name: str,
+ second_device_name: str,
+ second_interface_name: str,
+) -> None:
+ # Connecting first interface to second interface
+ first_interface = store.get(kind=interface_kind, key=first_interface_name)
+ second_interface = store.get(kind=interface_kind, key=second_interface_name)
+
+ first_interface.description.value = f"Connected to {second_device_name}::{second_interface.name.value}"
+ first_interface.connected_endpoint = second_interface
+ batch.add(task=first_interface.save, node=first_interface)
+
+ # Adjust description on second interface
+ second_interface.description.value = f"Connected to {first_device_name}::{first_interface.name.value}"
+ batch.add(task=second_interface.save, node=second_interface)
+
+ log.info(
+ f" - Connected '{first_device_name}::{first_interface_name}' <> '{second_device_name}::{second_interface_name}'"
+ )
+
+
async def apply_interface_profiles(client: InfrahubClient, log: logging.Logger, branch: str) -> None:
# ------------------------------------------
# Add profile on interfaces upstream/backbone
# ------------------------------------------
log.info("Starting to apply profiles to interfaces")
- upstream_interfaces = await client.filters(branch=branch, kind="InfraInterfaceL3", role__value="upstream")
- backbone_interfaces = await client.filters(branch=branch, kind="InfraInterfaceL3", role__value="backbone")
- upstream_profile = store.get(key="upstream_profile", kind="ProfileInfraInterfaceL3")
- backbone_profile = store.get(key="backbone_profile", kind="ProfileInfraInterfaceL3")
+ upstream_interfaces = await client.filters(branch=branch, kind=InfraInterfaceL3, role__value="upstream")
+ backbone_interfaces = await client.filters(branch=branch, kind=InfraInterfaceL3, role__value="backbone")
+ upstream_profile = store.get(key="upstream_profile", kind="ProfileInfraInterfaceL3", raise_when_missing=True)
+ backbone_profile = store.get(key="backbone_profile", kind="ProfileInfraInterfaceL3", raise_when_missing=True)
batch = await client.create_batch()
for interface in upstream_interfaces:
@@ -550,8 +760,8 @@ async def create_backbone_connectivity(
# CREATE Backbone Links & Circuits
# --------------------------------------------------
log.info("Creating Backbone Links & Circuits")
- account_pop = store.get("pop-builder")
- interconnection_pool = store.get("interconnection_pool")
+ account_pop = store.get("pop-builder", kind=CoreAccount, raise_when_missing=True)
+ interconnection_pool = store.get("interconnection_pool", kind=CoreAccount, raise_when_missing=True)
networks: list[P2pNetwork] = []
@@ -566,7 +776,7 @@ async def create_backbone_connectivity(
for network in networks:
network.pool = await client.allocate_next_ip_prefix(
- resource_pool=interconnection_pool, branch=branch, identifier=network.identifier
+ resource_pool=interconnection_pool, kind=IpamIPPrefix, branch=branch, identifier=network.identifier
)
log.info("- Done allocating addresses")
@@ -575,12 +785,12 @@ async def create_backbone_connectivity(
intf1 = INTERFACE_OBJS[backbone_link.site1_device].pop(0)
intf2 = INTERFACE_OBJS[backbone_link.site2_device].pop(0)
- backbone_link_ips = backbone_link.pool.prefix.value.hosts()
+ backbone_link_ips = backbone_link.get_pool().prefix.value.hosts()
provider = store.get(kind="OrganizationProvider", key=backbone_link.provider_name)
obj = await client.create(
branch=branch,
- kind="InfraCircuit",
+ kind=InfraCircuit,
description=f"Backbone {backbone_link.site1} <-> {backbone_link.site2}",
circuit_id=backbone_link.circuit,
vendor_id=f"{backbone_link.provider_name.upper()}-{UUIDT().short()}",
@@ -594,7 +804,7 @@ async def create_backbone_connectivity(
# Create Circuit Endpoints
endpoint1 = await client.create(
branch=branch,
- kind="InfraCircuitEndpoint",
+ kind=InfraCircuitEndpoint,
description=f"Endpoint {backbone_link.circuit} to {backbone_link.site1_device}",
site=backbone_link.site1,
circuit=obj,
@@ -604,7 +814,7 @@ async def create_backbone_connectivity(
endpoint2 = await client.create(
branch=branch,
- kind="InfraCircuitEndpoint",
+ kind=InfraCircuitEndpoint,
description=f"Endpoint {backbone_link.circuit} to {backbone_link.site2_device}",
site=backbone_link.site2,
circuit=obj,
@@ -617,25 +827,25 @@ async def create_backbone_connectivity(
intf21_address = f"{str(next(backbone_link_ips))}/31"
intf11_ip = await client.create(
branch=branch,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
interface={"id": intf1.id, "source": account_pop.id},
address={"value": intf11_address, "source": account_pop.id},
)
await intf11_ip.save()
intf21_ip = await client.create(
branch=branch,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
interface={"id": intf2.id, "source": account_pop.id},
address={"value": intf21_address, "source": account_pop.id},
)
await intf21_ip.save()
# Update Interface
- intf11 = await client.get(branch=branch, kind="InfraInterfaceL3", id=intf1.id)
+ intf11 = await client.get(branch=branch, kind=InfraInterfaceL3, id=intf1.id)
intf11.description.value = f"Backbone: Connected to {backbone_link.site2_device} via {backbone_link.circuit}"
await intf11.save()
- intf21 = await client.get(branch=branch, kind="InfraInterfaceL3", id=intf2.id)
+ intf21 = await client.get(branch=branch, kind=InfraInterfaceL3, id=intf2.id)
intf21.description.value = f"Backbone: Connected to {backbone_link.site1_device} via {backbone_link.circuit}"
await intf21.save()
@@ -651,7 +861,7 @@ async def create_bgp_mesh(client: InfrahubClient, log: logging.Logger, branch: s
log.info("Creating Full Mesh iBGP SESSION between all the Edge devices")
batch = await client.create_batch()
num_sites = len(sites)
- internal_as = store.get(kind="InfraAutonomousSystem", key="Duff")
+ internal_as = store.get(kind=InfraAutonomousSystem, key="Duff", raise_when_missing=True)
for site1 in sites:
for site2 in sites:
@@ -663,8 +873,8 @@ async def create_bgp_mesh(client: InfrahubClient, log: logging.Logger, branch: s
device1 = f"{site1.name}-edge{idx1}"
device2 = f"{site2.name}-edge{idx2}"
- loopback1 = store.get(key=f"{device1}-loopback")
- loopback2 = store.get(key=f"{device2}-loopback")
+ loopback1 = store.get(key=f"{device1}-loopback", kind=InfraInterfaceL3, raise_when_missing=True)
+ loopback2 = store.get(key=f"{device2}-loopback", kind=InfraInterfaceL3, raise_when_missing=True)
peer_group_name = "POP_GLOBAL"
@@ -676,8 +886,8 @@ async def create_bgp_mesh(client: InfrahubClient, log: logging.Logger, branch: s
local_ip=loopback1.id,
remote_as=internal_as.id,
remote_ip=loopback2.id,
- peer_group=store.get(key=peer_group_name).id,
- device=store.get(kind="InfraDevice", key=device1).id,
+ peer_group=store.get(key=peer_group_name, raise_when_missing=True).id,
+ device=store.get(kind=InfraDevice, key=device1, raise_when_missing=True).id,
status=ACTIVE_STATUS,
role=BACKBONE_ROLE,
)
@@ -694,15 +904,15 @@ async def create_bgp_mesh(client: InfrahubClient, log: logging.Logger, branch: s
async def generate_site_vlans(
client: InfrahubClient, log: logging.Logger, branch: str, site: Site, site_id: int
) -> None:
- account_pop = store.get("pop-builder")
- group_eng = store.get("Engineering Team")
- group_ops = store.get("Operation Team")
+ account_pop = store.get("pop-builder", kind=CoreAccount, raise_when_missing=True)
+ group_eng = store.get("Engineering Team", kind=CoreAccount, raise_when_missing=True)
+ group_ops = store.get("Operation Team", kind=CoreAccount, raise_when_missing=True)
for vlan in VLANS:
vlan_name = f"{site.name}_{vlan.role}"
obj = await client.create(
branch=branch,
- kind="InfraVLAN",
+ kind=InfraVLAN,
site={"id": site_id, "source": account_pop.id, "is_protected": True},
name={"value": vlan_name, "is_protected": True, "source": account_pop.id},
vlan_id={"value": vlan.id, "is_protected": True, "owner": group_eng.id, "source": account_pop.id},
@@ -719,18 +929,18 @@ async def generate_site_mlag_domain(client: InfrahubClient, log: logging.Logger,
# --------------------------------------------------
for role, domain in MLAG_DOMAINS.items():
devices = [
- store.get(kind="InfraDevice", key=f"{site.name}-{role}1"),
- store.get(kind="InfraDevice", key=f"{site.name}-{role}2"),
+ store.get(kind=InfraDevice, key=f"{site.name}-{role}1"),
+ store.get(kind=InfraDevice, key=f"{site.name}-{role}2"),
]
name = f"{site.name}-{role}-12"
peer_interfaces = [
- store.get(kind="InfraLagInterfaceL2", key=f"{device_obj.name.value}-lagl2-{domain['peer_interfaces'][idx]}")
+ store.get(kind=InfraLagInterfaceL2, key=f"{device_obj.name.value}-lagl2-{domain['peer_interfaces'][idx]}") # type: ignore[index]
for idx, device_obj in enumerate(devices)
]
mlag_domain = await client.create(
- kind="InfraMlagDomain",
+ kind=InfraMlagDomain,
name=name,
domain_id=domain["domain_id"],
devices=devices,
@@ -745,19 +955,19 @@ async def generate_site_mlag_domain(client: InfrahubClient, log: logging.Logger,
# --------------------------------------------------
for role, mlags in MLAG_INTERFACE_L2.items():
devices = [
- store.get(kind="InfraDevice", key=f"{site.name}-{role}1"),
- store.get(kind="InfraDevice", key=f"{site.name}-{role}2"),
+ store.get(kind=InfraDevice, key=f"{site.name}-{role}1"),
+ store.get(kind=InfraDevice, key=f"{site.name}-{role}2"),
]
for mlag in mlags:
members = [
- store.get(kind="InfraLagInterfaceL2", key=f"{device_obj.name.value}-lagl2-{mlag['members'][idx]}")
+ store.get(kind=InfraLagInterfaceL2, key=f"{device_obj.name.value}-lagl2-{mlag['members'][idx]}") # type: ignore[index]
for idx, device_obj in enumerate(devices)
]
- mlag_domain = store.get(kind="InfraMlagDomain", key=f"mlag-domain-{site.name}-{role}-12")
+ mlag_domain = store.get(kind=InfraMlagDomain, key=f"mlag-domain-{site.name}-{role}-12")
mlag_interface = await client.create(
- kind="InfraMlagInterfaceL2", mlag_domain=mlag_domain, mlag_id=mlag["mlag_id"], members=members
+ kind=InfraMlagInterfaceL2, mlag_domain=mlag_domain, mlag_id=mlag["mlag_id"], members=members
)
await mlag_interface.save()
@@ -768,18 +978,19 @@ async def generate_site(
log: logging.Logger,
branch: str,
site: Site,
- interconnection_pool: InfrahubNode,
- loopback_pool: InfrahubNode,
- management_pool: InfrahubNode,
- external_pool: InfrahubNode,
+ interconnection_pool: CoreNode,
+ loopback_pool: CoreNode,
+ management_pool: CoreNode,
+ external_pool: CoreNode,
+ site_design: SiteDesign,
) -> str:
- group_eng = store.get("Engineering Team")
- group_ops = store.get("Operation Team")
- account_pop = store.get("pop-builder")
- account_crm = store.get("CRM Synchronization")
- internal_as = store.get(kind="InfraAutonomousSystem", key="Duff")
+ group_eng = store.get("Engineering Team", kind=CoreAccount)
+ group_ops = store.get("Operation Team", kind=CoreAccount)
+ account_pop = store.get("pop-builder", kind=CoreAccount)
+ account_crm = store.get("CRM Synchronization", kind=CoreAccount)
+ internal_as = store.get(kind=InfraAutonomousSystem, key="Duff")
- country = store.get(kind="LocationCountry", key=site.country)
+ country = store.get(kind=LocationCountry, key=site.country)
# --------------------------------------------------
# Create the Site
# --------------------------------------------------
@@ -799,33 +1010,62 @@ async def generate_site(
# --------------------------------------------------
# Create the site specific IP prefixes
# --------------------------------------------------
- peer_networks = [
- await client.allocate_next_ip_prefix(resource_pool=interconnection_pool, branch=branch),
- await client.allocate_next_ip_prefix(resource_pool=interconnection_pool, branch=branch),
- ]
- peer_network_hosts = {0: peer_networks[0].prefix.value.hosts(), 1: peer_networks[1].prefix.value.hosts()}
+ # TODO: Refactor that part for the sake of readability
+ # Here we dispatch to every p2p a /31 prefixe
+ # Between two edges we have 2 p2p connections so 2 prefixes
+ # So far we connect edge1<->edge2 then edge3<->edge4 ...
+ peer_networks: list[IpamIPPrefix] = []
+ peer_network_hosts = {
+ # 0: {0: peer_networks[0].prefix.value.hosts(), 1: peer_networks[1].prefix.value.hosts()},
+ # ^ Device id ^ interface id
+ }
- group_core_router_members = []
- group_edge_router_members = []
- group_cisco_devices_members = []
- group_arista_devices_members = []
+ # Here we need as much prefix as we have edge device
+ for i in range(site_design.num_edge_device):
+ peer_networks.append(
+ await client.allocate_next_ip_prefix(resource_pool=interconnection_pool, kind=IpamIPPrefix, branch=branch)
+ )
+
+ # Then we prepare all ips for all interfaces
+ # TODO: Refactor that part for the sake of readability
+ for i in range(1, site_design.num_edge_device, 2):
+ peer_network_hosts[i] = {
+ 0: peer_networks[i - 1].prefix.value.hosts(),
+ 1: peer_networks[i].prefix.value.hosts(),
+ }
+ peer_network_hosts[i + 1] = {
+ 0: peer_networks[i - 1].prefix.value.hosts(),
+ 1: peer_networks[i].prefix.value.hosts(),
+ }
+
+ group_core_router_members: list[str] = []
+ group_edge_router_members: list[str] = []
+ group_cisco_devices_members: list[str] = []
+ group_arista_devices_members: list[str] = []
group_upstream_interfaces_members = []
group_backbone_interfaces_members = []
- for idx, device in enumerate(DEVICES):
+ # --------------------------------------------------
+ # Create devices
+ # --------------------------------------------------
+ # Craft the list of devices
+ devices: list[Device] = site_design.implement()
+
+ # TODO: There is room for improvement here, batch those device together
+ for device in devices:
device_name = f"{site.name}-{device.name}"
- platform_id = store.get(kind="InfraPlatform", key=device.platform).id
+ platform_id = store.get(kind=InfraPlatform, key=device.platform).id
obj = await client.create(
branch=branch,
- kind="InfraDevice",
+ kind=InfraDevice,
site={"id": site_obj.id, "source": account_pop.id, "is_protected": True},
name={"value": device_name, "source": account_pop.id, "is_protected": True},
status={"value": device.status, "owner": group_ops.id},
type={"value": device.type, "source": account_pop.id},
role={"value": device.role, "source": account_pop.id, "is_protected": True, "owner": group_eng.id},
asn={"id": internal_as.id, "source": account_pop.id, "is_protected": True, "owner": group_eng.id},
- tags=[store.get(kind="BuiltinTag", key=tag_name).id for tag_name in device.tags],
+ tags=[store.get(kind="BuiltinTag", key=tag_name, raise_when_missing=True).id for tag_name in device.tags],
platform={"id": platform_id, "source": account_pop.id, "is_protected": True},
)
await obj.save()
@@ -846,7 +1086,7 @@ async def generate_site(
# Loopback Interface
intf = await client.create(
branch=branch,
- kind="InfraInterfaceL3",
+ kind=InfraInterfaceL3,
device={"id": obj.id, "is_protected": True},
name={"value": "Loopback0", "source": account_pop.id, "is_protected": True},
enabled=True,
@@ -864,7 +1104,7 @@ async def generate_site(
# Management Interface
intf = await client.create(
branch=branch,
- kind="InfraInterfaceL3",
+ kind=InfraInterfaceL3,
device={"id": obj.id, "is_protected": True},
name={"value": INTERFACE_MGMT_NAME[device.type], "source": account_pop.id},
enabled={"value": True, "owner": group_eng.id},
@@ -876,18 +1116,20 @@ async def generate_site(
management_ip = await client.allocate_next_ip_address(
resource_pool=management_pool, identifier=device_name, data={"interface": intf.id}, branch=branch
)
+ management_ip = cast(IpamIPAddress, management_ip)
# set the IP address of the device to the management interface IP address
- obj.primary_address = management_ip
+ obj.primary_address = management_ip # type: ignore[assignment]
await obj.save()
# L3 Interfaces
+ # TODO: There is room for improvement here
for intf_idx, intf_name in enumerate(device.l3_interface_names):
intf_role = INTERFACE_L3_ROLES_MAPPING[device.role][intf_idx]
intf = await client.create(
branch=branch,
- kind="InfraInterfaceL3",
+ kind=InfraInterfaceL3,
device={"id": obj.id, "is_protected": True},
name=intf_name,
speed=10000,
@@ -905,14 +1147,18 @@ async def generate_site(
subnet = None
address = None
if intf_role == "peer":
- address = f"{str(next(peer_network_hosts[intf_idx]))}/31"
+ # TODO: Refactor that part for the sake of readability
+ address = f"{str(next(peer_network_hosts[device._idx][intf_idx]))}/31"
if intf_role == "upstream":
group_upstream_interfaces_members.append(intf.id)
if intf_role in ["upstream", "peering"] and "edge" in device.role:
subnet = await client.allocate_next_ip_prefix(
- resource_pool=external_pool, identifier=f"{device_name}__{intf_role}__{intf_idx}", branch=branch
+ kind=IpamIPPrefix,
+ resource_pool=external_pool,
+ identifier=f"{device_name}__{intf_role}__{intf_idx}",
+ branch=branch,
)
subnet_hosts = subnet.prefix.value.hosts()
address = f"{str(next(subnet_hosts))}/29"
@@ -921,7 +1167,7 @@ async def generate_site(
if address:
ip = await client.create(
branch=branch,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
interface={"id": intf.id, "source": account_pop.id},
address={"value": address, "source": account_pop.id},
)
@@ -938,11 +1184,11 @@ async def generate_site(
elif intf_role == "peering":
provider_name = "Equinix"
- provider = store.get(kind="OrganizationProvider", key=provider_name)
+ provider = store.get(kind=OrganizationProvider, key=provider_name, raise_when_missing=True)
circuit = await client.create(
branch=branch,
- kind="InfraCircuit",
+ kind=InfraCircuit,
circuit_id=circuit_id,
vendor_id=f"{provider_name.upper()}-{UUIDT().short()}",
provider=provider.id,
@@ -954,7 +1200,7 @@ async def generate_site(
endpoint1 = await client.create(
branch=branch,
- kind="InfraCircuitEndpoint",
+ kind=InfraCircuitEndpoint,
site=site_obj,
circuit=circuit.id,
connected_endpoint=intf.id,
@@ -970,22 +1216,22 @@ async def generate_site(
peer_ip = await client.create(
branch=branch,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
address=peer_address,
)
await peer_ip.save()
- peer_as = store.get(kind="InfraAutonomousSystem", key=provider_name)
+ peer_as = store.get(kind=InfraAutonomousSystem, key=provider_name)
bgp_session = await client.create(
branch=branch,
- kind="InfraBGPSession",
+ kind=InfraBGPSession,
type="EXTERNAL",
local_as=internal_as.id,
local_ip=ip.id,
remote_as=peer_as.id,
remote_ip=peer_ip.id,
- peer_group=store.get(key=peer_group_name).id,
- device=store.get(key=device_name).id,
+ peer_group=store.get(key=peer_group_name, raise_when_missing=True).id,
+ device=store.get(key=device_name, raise_when_missing=True).id,
status=ACTIVE_STATUS,
role=intf_role,
)
@@ -1009,11 +1255,11 @@ async def generate_site(
untagged_vlan = None
if l2_mode == "Access":
- untagged_vlan = store.get(kind="InfraVLAN", key=f"{site.name}_server")
+ untagged_vlan = store.get(kind=InfraVLAN, key=f"{site.name}_server")
intf = await client.create(
branch=branch,
- kind="InfraInterfaceL2",
+ kind=InfraInterfaceL2,
device={"id": obj.id, "is_protected": True},
name=intf_name,
speed=10000,
@@ -1032,7 +1278,7 @@ async def generate_site(
for lag_intf in LAG_INTERFACE_L2.get(device.type, []):
try:
- intf_role = LAG_INTERFACE_L2_ROLES_MAPPING[device.role][lag_intf["name"]]
+ intf_role = LAG_INTERFACE_L2_ROLES_MAPPING[device.role][lag_intf["name"]] # type: ignore[index]
except KeyError:
intf_role = "server"
@@ -1042,11 +1288,11 @@ async def generate_site(
untagged_vlan = None
if l2_mode == "Access":
- untagged_vlan = store.get(kind="InfraVLAN", key=f"{site.name}_server")
+ untagged_vlan = store.get(kind=InfraVLAN, key=f"{site.name}_server")
lag = await client.create(
branch=branch,
- kind="InfraLagInterfaceL2",
+ kind=InfraLagInterfaceL2,
device={"id": obj.id, "is_protected": True},
name=lag_intf["name"],
description=description,
@@ -1063,118 +1309,112 @@ async def generate_site(
store.set(key=f"{device_name}-lagl2-{lag_intf['name']}", node=lag)
- members = [store.get(key=f"{device_name}-l2-{member}").id for member in lag_intf["members"]]
+ members = [
+ store.get(key=f"{device_name}-l2-{member}", raise_when_missing=True).id
+ for member in lag_intf["members"]
+ ]
await lag.add_relationships(relation_to_update="members", related_nodes=members)
await generate_site_mlag_domain(client=client, log=log, branch=branch, site=site)
+ # Create a batch for all those connections
+ batch_interface: InfrahubBatch = await client.create_batch()
+
# --------------------------------------------------
- # Connect both devices within the Site together with 2 interfaces
+ # Connect edge devices 2 by 2
# --------------------------------------------------
- for idx in range(2):
- intf1 = store.get(kind="InfraInterfaceL3", key=f"{site.name}-edge1-l3-{idx}")
- intf2 = store.get(kind="InfraInterfaceL3", key=f"{site.name}-edge2-l3-{idx}")
-
- intf1.description.value = f"Connected to {site.name}-edge2 {intf2.name.value}"
- intf1.connected_endpoint = intf2
- await intf1.save()
-
- intf2.description.value = f"Connected to {site.name}-edge1 {intf1.name.value}"
- await intf2.save()
+ for idx in range(1, site_design.num_edge_device, 2):
+ # Connecting eth 0 to eth 0
+ await find_and_connect_interfaces(
+ batch_interface,
+ log,
+ InfraInterfaceL3,
+ f"{site.name}-edge{idx}",
+ f"{site.name}-edge{idx}-l3-0",
+ f"{site.name}-edge{idx + 1}",
+ f"{site.name}-edge{idx + 1}-l3-0",
+ )
- log.info(f" - Connected '{site.name}-edge1::{intf1.name.value}' <> '{site.name}-edge2::{intf2.name.value}'")
+ # Connecting eth 1 to eth 1
+ await find_and_connect_interfaces(
+ batch_interface,
+ log,
+ InfraInterfaceL3,
+ f"{site.name}-edge{idx}",
+ f"{site.name}-edge{idx}-l3-1",
+ f"{site.name}-edge{idx + 1}",
+ f"{site.name}-edge{idx + 1}-l3-1",
+ )
# --------------------------------------------------
- # Connect both leaf devices within a Site together with the 2 peer interfaces
+ # Connect leaf devices 2 by 2
# --------------------------------------------------
- for idx in range(2):
- intf1 = store.get(kind="InfraInterfaceL2", key=f"{site.name}-leaf1-l2-Ethernet{idx + 1}")
- intf2 = store.get(kind="InfraInterfaceL2", key=f"{site.name}-leaf2-l2-Ethernet{idx + 1}")
-
- intf1.description.value = f"Connected to {site.name}-leaf2 {intf2.name.value}"
- intf1.connected_endpoint = intf2
- await intf1.save()
+ for idx in range(1, site_design.num_leaf_device, 2):
+ # Connecting eth 1 to eth 1
+ await find_and_connect_interfaces(
+ batch_interface,
+ log,
+ InfraInterfaceL2,
+ f"{site.name}-leaf{idx}",
+ f"{site.name}-leaf{idx}-l2-Ethernet1",
+ f"{site.name}-leaf{idx + 1}",
+ f"{site.name}-leaf{idx + 1}-l2-Ethernet1",
+ )
- intf2.description.value = f"Connected to {site.name}-leaf1 {intf1.name.value}"
- await intf2.save()
+ # Connecting eth 2 to eth 2
+ await find_and_connect_interfaces(
+ batch_interface,
+ log,
+ InfraInterfaceL2,
+ f"{site.name}-leaf{idx}",
+ f"{site.name}-leaf{idx}-l2-Ethernet2",
+ f"{site.name}-leaf{idx + 1}",
+ f"{site.name}-leaf{idx + 1}-l2-Ethernet2",
+ )
- log.info(f" - Connected '{site.name}-leaf1::{intf1.name.value}' <> '{site.name}-leaf2::{intf2.name.value}'")
+ async for node, _ in batch_interface.execute():
+ log.info(f"- Saving {node._schema.kind} - {node.name.value}")
# --------------------------------------------------
# Update all the group we may have touched during the site creation
# --------------------------------------------------
-
if group_edge_router_members:
- group_edge_router = store.get(kind="CoreStandardGroup", key="edge_router")
+ group_edge_router = store.get(kind=CoreStandardGroup, key="edge_router")
await group_edge_router.add_relationships(relation_to_update="members", related_nodes=group_edge_router_members)
if group_core_router_members:
- group_core_router = store.get(kind="CoreStandardGroup", key="core_router")
+ group_core_router = store.get(kind=CoreStandardGroup, key="core_router")
await group_core_router.add_relationships(relation_to_update="members", related_nodes=group_core_router_members)
if group_cisco_devices_members:
- group_cisco_devices = store.get(kind="CoreStandardGroup", key="cisco_devices")
+ group_cisco_devices = store.get(kind=CoreStandardGroup, key="cisco_devices")
await group_cisco_devices.add_relationships(
relation_to_update="members", related_nodes=group_cisco_devices_members
)
+
if group_arista_devices_members:
- group_arista_devices = store.get(kind="CoreStandardGroup", key="arista_devices")
+ group_arista_devices = store.get(kind=CoreStandardGroup, key="arista_devices")
await group_arista_devices.add_relationships(
relation_to_update="members", related_nodes=group_arista_devices_members
)
if group_upstream_interfaces_members:
- group_upstream_interfaces = store.get(kind="CoreStandardGroup", key="upstream_interfaces")
+ group_upstream_interfaces = store.get(kind=CoreStandardGroup, key="upstream_interfaces")
await group_upstream_interfaces.add_relationships(
relation_to_update="members", related_nodes=group_upstream_interfaces_members
)
if group_backbone_interfaces_members:
- group_backbone_interfaces = store.get(kind="CoreStandardGroup", key="backbone_interfaces")
+ group_backbone_interfaces = store.get(kind=CoreStandardGroup, key="backbone_interfaces")
await group_backbone_interfaces.add_relationships(
relation_to_update="members", related_nodes=group_backbone_interfaces_members
)
- # --------------------------------------------------
- # Create iBGP Sessions within the Site
- # --------------------------------------------------
- for idx in range(2):
- if idx == 0:
- device1 = f"{site.name}-{DEVICES[0].name}"
- device2 = f"{site.name}-{DEVICES[1].name}"
- elif idx == 1:
- device1 = f"{site.name}-{DEVICES[1].name}"
- device2 = f"{site.name}-{DEVICES[0].name}"
-
- peer_group_name = "POP_INTERNAL"
-
- loopback1 = store.get(key=f"{device1}-loopback")
- loopback2 = store.get(key=f"{device2}-loopback")
-
- obj = await client.create(
- branch=branch,
- kind="InfraBGPSession",
- type="INTERNAL",
- local_as=internal_as.id,
- local_ip=loopback1.id,
- remote_as=internal_as.id,
- remote_ip=loopback2.id,
- peer_group=store.get(key=peer_group_name).id,
- device=store.get(kind="InfraDevice", key=device1).id,
- status=ACTIVE_STATUS,
- role=BACKBONE_ROLE,
- )
- await obj.save()
-
- log.info(
- f" - Created BGP Session '{device1}' >> '{device2}': '{peer_group_name}' '{loopback1.address.value}' >> '{loopback2.address.value}'"
- )
-
return site.name
async def branch_scenario_add_upstream(
- client: InfrahubClient, log: logging.Logger, site_name: str, external_pool: InfrahubNode
+ client: InfrahubClient, log: logging.Logger, site_name: str, external_pool: CoreNode
) -> None:
"""
Create a new branch and Add a new upstream link with GTT on the edge1 device of the given site.
@@ -1188,16 +1428,16 @@ async def branch_scenario_add_upstream(
)
log.info(f"- Creating branch: {new_branch_name!r}")
# Querying the object for now, need to pull from the store instead
- site = await client.get(branch=new_branch_name, kind="LocationSite", name__value=site_name)
- device = await client.get(branch=new_branch_name, kind="InfraDevice", name__value=device_name)
+ site = await client.get(branch=new_branch_name, kind=LocationSite, name__value=site_name)
+ device = await client.get(branch=new_branch_name, kind=InfraDevice, name__value=device_name)
gtt_organization = await client.get(
- branch=new_branch_name, kind="OrganizationProvider", name__value="GTT Communications"
+ branch=new_branch_name, kind=OrganizationProvider, name__value="GTT Communications"
)
role_spare = "spare"
intfs = await client.filters(
- branch=new_branch_name, kind="InfraInterfaceL3", device__ids=[device.id], role__value=role_spare
+ branch=new_branch_name, kind=InfraInterfaceL3, device__ids=[device.id], role__value=role_spare
)
intf = intfs[0]
log.info(f" - Adding new Upstream on '{device_name}::{intf.name.value}'")
@@ -1206,20 +1446,21 @@ async def branch_scenario_add_upstream(
subnet = await client.allocate_next_ip_prefix(
resource_pool=external_pool, identifier=device_name, branch=new_branch_name
)
+ subnet = cast(IpamIPPrefix, subnet)
subnet_hosts = subnet.prefix.value.hosts()
address = f"{str(next(subnet_hosts))}/29"
peer_address = f"{str(next(subnet_hosts))}/29"
peer_ip = await client.create(
branch=new_branch_name,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
address=peer_address,
)
await peer_ip.save()
ip = await client.create(
branch=new_branch_name,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
interface={"id": intf.id},
address={"value": address},
)
@@ -1230,7 +1471,7 @@ async def branch_scenario_add_upstream(
circuit = await client.create(
branch=new_branch_name,
- kind="InfraCircuit",
+ kind=InfraCircuit,
circuit_id=circuit_id,
vendor_id=f"{gtt_organization.name.value.upper()}-{UUIDT().short()}",
provider=gtt_organization.id,
@@ -1242,7 +1483,7 @@ async def branch_scenario_add_upstream(
endpoint1 = await client.create(
branch=new_branch_name,
- kind="InfraCircuitEndpoint",
+ kind=InfraCircuitEndpoint,
site=site,
circuit=circuit.id,
connected_endpoint=intf.id,
@@ -1283,7 +1524,7 @@ async def branch_scenario_add_upstream(
async def branch_scenario_replace_ip_addresses(
- client: InfrahubClient, log: logging.Logger, site_name: str, interconnection_pool: InfrahubNode
+ client: InfrahubClient, log: logging.Logger, site_name: str, interconnection_pool: CoreNode
) -> None:
"""
Create a new Branch and Change the IP addresses between edge1 and edge2 on the selected site
@@ -1301,23 +1542,26 @@ async def branch_scenario_replace_ip_addresses(
log.info(f"- Creating branch: {new_branch_name!r}")
new_peer_network = await client.allocate_next_ip_prefix(
- resource_pool=interconnection_pool, identifier=f"{device1_name}__{device2_name}", branch=new_branch_name
+ kind=IpamIPPrefix,
+ resource_pool=interconnection_pool,
+ identifier=f"{device1_name}__{device2_name}",
+ branch=new_branch_name,
)
new_peer_network_hosts = new_peer_network.prefix.value.hosts()
- device1 = await client.get(branch=new_branch_name, kind="InfraDevice", name__value=device1_name)
- device2 = await client.get(branch=new_branch_name, kind="InfraDevice", name__value=device2_name)
+ device1 = await client.get(branch=new_branch_name, kind=InfraDevice, name__value=device1_name)
+ device2 = await client.get(branch=new_branch_name, kind=InfraDevice, name__value=device2_name)
role_peer = "peer"
peer_intfs_dev1 = sorted(
await client.filters(
- branch=new_branch_name, kind="InfraInterfaceL3", device__ids=[device1.id], role__value=role_peer
+ branch=new_branch_name, kind=InfraInterfaceL3, device__ids=[device1.id], role__value=role_peer
),
key=lambda x: x.name.value,
)
peer_intfs_dev2 = sorted(
await client.filters(
- branch=new_branch_name, kind="InfraInterfaceL3", device__ids=[device2.id], role__value=role_peer
+ branch=new_branch_name, kind=InfraInterfaceL3, device__ids=[device2.id], role__value=role_peer
),
key=lambda x: x.name.value,
)
@@ -1325,7 +1569,7 @@ async def branch_scenario_replace_ip_addresses(
# Querying the object for now, need to pull from the store instead
peer_ip = await client.create(
branch=new_branch_name,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
interface={"id": peer_intfs_dev1[0].id},
address=f"{str(next(new_peer_network_hosts))}/31",
)
@@ -1334,7 +1578,7 @@ async def branch_scenario_replace_ip_addresses(
ip = await client.create(
branch=new_branch_name,
- kind="IpamIPAddress",
+ kind=IpamIPAddress,
interface={"id": peer_intfs_dev2[0].id}, # , "source": account_pop.id},
address={"value": f"{str(next(new_peer_network_hosts))}/31"}, # , "source": account_pop.id},
)
@@ -1399,12 +1643,10 @@ async def branch_scenario_remove_colt(client: InfrahubClient, log: logging.Logge
for item in colt_circuits:
circuit_id = item["node"]["circuit"]["node"]["circuit_id"]["value"]
- circuit_endpoint = await client.get(branch=new_branch_name, kind="InfraCircuitEndpoint", id=item["node"]["id"])
+ circuit_endpoint = await client.get(branch=new_branch_name, kind=InfraCircuitEndpoint, id=item["node"]["id"])
await circuit_endpoint.delete()
- circuit = await client.get(
- branch=new_branch_name, kind="InfraCircuit", id=item["node"]["circuit"]["node"]["id"]
- )
+ circuit = await client.get(branch=new_branch_name, kind=InfraCircuit, id=item["node"]["circuit"]["node"]["id"])
await circuit.delete()
log.info(f" - Deleted Colt Technology Services [{circuit_id}]")
@@ -1430,24 +1672,24 @@ async def branch_scenario_conflict_device(client: InfrahubClient, log: logging.L
drained_status = "drained"
# Update Device 1 Status both in the Branch and in Main
- device1_branch = await client.get(branch=new_branch_name, kind="InfraDevice", name__value=device1_name)
+ device1_branch = await client.get(branch=new_branch_name, kind=InfraDevice, name__value=device1_name)
device1_branch.status.value = maintenance_status
await device1_branch.save()
intf1_branch = await client.get(
- branch=new_branch_name, kind="InfraInterfaceL3", device__ids=[device1_branch.id], name__value="Ethernet1"
+ branch=new_branch_name, kind=InfraInterfaceL3, device__ids=[device1_branch.id], name__value="Ethernet1"
)
intf1_branch.enabled.value = False
intf1_branch.status.value = drained_status
await intf1_branch.save()
- device1_main = await client.get(kind="InfraDevice", name__value=device1_name)
+ device1_main = await client.get(kind=InfraDevice, name__value=device1_name)
device1_main.status.value = provisioning_status
await device1_main.save()
- intf1_main = await client.get(kind="InfraInterfaceL3", device__ids=[device1_branch.id], name__value="Ethernet1")
+ intf1_main = await client.get(kind=InfraInterfaceL3, device__ids=[device1_branch.id], name__value="Ethernet1")
intf1_main.enabled.value = False
await intf1_main.save()
@@ -1467,22 +1709,22 @@ async def branch_scenario_conflict_platform(client: InfrahubClient, log: logging
# Create a new Platform object with the same name, both in the branch and in main
platform1_branch = await client.create(
- branch=new_branch_name, kind="InfraPlatform", name="Cisco IOS XR", netmiko_device_type="cisco_xr"
+ branch=new_branch_name, kind=InfraPlatform, name="Cisco IOS XR", netmiko_device_type="cisco_xr"
)
await platform1_branch.save()
- platform1_main = await client.create(kind="InfraPlatform", name="Cisco IOS XR", netmiko_device_type="cisco_xr")
+ platform1_main = await client.create(kind=InfraPlatform, name="Cisco IOS XR", netmiko_device_type="cisco_xr")
await platform1_main.save()
# Delete an existing Platform object on both in the Branch and in Main
- platform2_branch = await client.get(branch=new_branch_name, kind="InfraPlatform", name__value="Cisco NXOS SSH")
+ platform2_branch = await client.get(branch=new_branch_name, kind=InfraPlatform, name__value="Cisco NXOS SSH")
await platform2_branch.delete()
- platform2_main = await client.get(kind="InfraPlatform", name__value="Cisco NXOS SSH")
+ platform2_main = await client.get(kind=InfraPlatform, name__value="Cisco NXOS SSH")
await platform2_main.delete()
# Delete an existing Platform object in the branch and update it in main
- platform3_branch = await client.get(branch=new_branch_name, kind="InfraPlatform", name__value="Juniper JunOS")
+ platform3_branch = await client.get(branch=new_branch_name, kind=InfraPlatform, name__value="Juniper JunOS")
await platform3_branch.delete()
- platform3_main = await client.get(kind="InfraPlatform", name__value="Juniper JunOS")
+ platform3_main = await client.get(kind=InfraPlatform, name__value="Juniper JunOS")
platform3_main.nornir_platform.value = "juniper_junos"
await platform3_main.save()
@@ -1514,19 +1756,21 @@ async def generate_continents_countries(client: InfrahubClient, log: logging.Log
async def prepare_accounts(client: InfrahubClient, log: logging.Logger, branch: str, batch: InfrahubBatch) -> None:
+ groups = await client.filters(branch=branch, kind=CoreAccountGroup, name__value="Super Administrators")
+ store.set(key=groups[0].name, node=groups[0])
+
for account in ACCOUNTS:
- obj = await client.create(
- branch=branch,
- kind="CoreAccount",
- data=account.model_dump(),
- )
+ data = account.model_dump()
+ data["member_of_groups"] = groups
+
+ obj = await client.create(branch=branch, kind="CoreAccount", data=data)
batch.add(task=obj.save, node=obj)
store.set(key=account.name, node=obj)
async def prepare_asns(client: InfrahubClient, log: logging.Logger, branch: str, batch: InfrahubBatch) -> None:
- account_chloe = store.get("Chloe O'Brian")
- account_crm = store.get("CRM Synchronization")
+ account_chloe = store.get("Chloe O'Brian", kind=CoreAccount, raise_when_missing=True)
+ account_crm = store.get("CRM Synchronization", kind=CoreAccount, raise_when_missing=True)
organizations_dict = {org.name: org.type for org in ORGANIZATIONS}
for asn in ASNS:
organization_type = organizations_dict.get(asn.organization, None)
@@ -1542,7 +1786,9 @@ async def prepare_asns(client: InfrahubClient, log: logging.Logger, branch: str,
"owner": account_chloe.id,
}
data_asn["organization"] = {
- "id": store.get(kind=f"Organization{organization_type.title()}", key=asn.organization).id,
+ "id": store.get(
+ kind=f"Organization{organization_type.title()}", raise_when_missing=True, key=asn.organization
+ ).id,
"source": account_crm.id,
}
else:
@@ -1555,7 +1801,7 @@ async def prepare_asns(client: InfrahubClient, log: logging.Logger, branch: str,
async def prepare_bgp_peer_groups(
client: InfrahubClient, log: logging.Logger, branch: str, batch: InfrahubBatch
) -> None:
- account_pop = store.get("pop-builder")
+ account_pop = store.get("pop-builder", kind=CoreAccount, raise_when_missing=True)
log.info("Creating BGP Peer Groups")
for peer_group in BGP_PEER_GROUPS:
@@ -1587,7 +1833,7 @@ async def prepare_bgp_peer_groups(
async def prepare_groups(client: InfrahubClient, log: logging.Logger, branch: str, batch: InfrahubBatch) -> None:
for group in GROUPS:
- obj = await client.create(branch=branch, kind="CoreStandardGroup", data=group.model_dump())
+ obj = await client.create(branch=branch, kind=CoreStandardGroup, data=group.model_dump())
batch.add(task=obj.save, node=obj)
store.set(key=group.name, node=obj)
@@ -1620,7 +1866,7 @@ async def prepare_platforms(client: InfrahubClient, log: logging.Logger, branch:
for platform in PLATFORMS:
obj = await client.create(
branch=branch,
- kind="InfraPlatform",
+ kind=InfraPlatform,
data=platform.model_dump(),
)
batch.add(task=obj.save, node=obj)
@@ -1628,7 +1874,7 @@ async def prepare_platforms(client: InfrahubClient, log: logging.Logger, branch:
async def prepare_tags(client: InfrahubClient, log: logging.Logger, branch: str, batch: InfrahubBatch) -> None:
- account_pop = store.get("pop-builder")
+ account_pop = store.get("pop-builder", kind=CoreAccount, raise_when_missing=True)
log.info("Creating Tags")
for tag in TAGS:
@@ -1642,12 +1888,55 @@ async def prepare_tags(client: InfrahubClient, log: logging.Logger, branch: str,
#
# infrahubctl run models/infrastructure_edge.py
#
+# You can also provide inputs to the script in order to generate more or less data
+#
+# infrahubctl run models/infrastructure_edge.py profile="large"
+# infrahubctl run models/infrastructure_edge.py num_sites=10 num_device_per_site=14
+# infrahubctl run models/infrastructure_edge.py has_bgp_mesh=False has_branch=False
+#
# ---------------------------------------------------------------
-async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_sites: int = 5) -> None:
+async def run(
+ client: InfrahubClient,
+ log: logging.Logger,
+ branch: str,
+ profile: str = None,
+ num_sites: int = None,
+ num_device_per_site: int = None,
+ has_bgp_mesh: str = None,
+ has_branch: str = None,
+) -> None:
+ # Create timer to keep track of time elapsed
+ start: float = time.time()
+
+ # ------------------------------------------
+ # Config
+ # ------------------------------------------
+ # Create an instance of the global configuration
+ config = GlobalConfig()
+
+ # Translate str to bool
+ bool_has_bgp_mesh: bool = None
+ if has_bgp_mesh is not None:
+ bool_has_bgp_mesh = translate_str_to_bool("has_bgp_mesh", has_bgp_mesh)
+
+ bool_has_branch: bool = None
+ if has_branch is not None:
+ bool_has_branch = translate_str_to_bool("has_branch", has_branch)
+
+ # Load args into the config
+ try:
+ config.load_config(profile, num_sites, num_device_per_site, bool_has_bgp_mesh, bool_has_branch)
+ except ConfigError as ex:
+ log.fatal(ex)
+ return False # FIXME: What should I return here for the script to fail properly
+
+ # Print config
+ log.info(f"Loading data with {config}")
+
# ------------------------------------------
# Create Continents, Countries
# ------------------------------------------
- num_sites = int(num_sites)
+ num_sites = int(config.num_sites)
log.info("Creating Infrastructure Data")
await generate_continents_countries(client=client, log=log, branch=branch)
@@ -1670,7 +1959,7 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
else:
log.info(f"- Created {node._schema.kind} - {node.name.value}")
- account_pop = store.get("pop-builder")
+ account_pop = store.get("pop-builder", kind=CoreAccount, raise_when_missing=True)
batch = await client.create_batch()
await prepare_asns(client=client, log=log, branch=branch, batch=batch)
@@ -1687,17 +1976,17 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
# ------------------------------------------
# Create IP prefixes
# ------------------------------------------
- default_ip_namespace = await client.get(kind="IpamNamespace", name__value="default")
+ default_ip_namespace = await client.get(kind=IpamNamespace, name__value="default")
log.info("Creating IP Prefixes")
log.info("Creating IP Core Supernet and Pool")
supernet_prefix = await client.create(
- branch=branch, kind="IpamIPPrefix", prefix=str(NETWORKS_SUPERNET), member_type="prefix"
+ branch=branch, kind=IpamIPPrefix, prefix=str(NETWORKS_SUPERNET), member_type="prefix"
)
await supernet_prefix.save()
supernet_pool = await client.create(
- kind="CoreIPPrefixPool",
+ kind=CoreIPPrefixPool,
name="Internal networks pool",
default_prefix_type="IpamIPPrefix",
default_prefix_length=16,
@@ -1712,7 +2001,7 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
resource_pool=supernet_pool, member_type="address", branch=branch
)
loopback_pool = await client.create(
- kind="CoreIPAddressPool",
+ kind=CoreIPAddressPool,
name="Loopbacks pool",
default_address_type="IpamIPAddress",
default_prefix_length=32,
@@ -1723,9 +2012,11 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
await loopback_pool.save()
log.info("Creating IP Interconnection Prefix and Pool")
- interconnection_prefix = await client.allocate_next_ip_prefix(resource_pool=supernet_pool, branch=branch)
+ interconnection_prefix = await client.allocate_next_ip_prefix(
+ kind=IpamIPPrefix, resource_pool=supernet_pool, branch=branch
+ )
interconnection_pool = await client.create(
- kind="CoreIPPrefixPool",
+ kind=CoreIPPrefixPool,
name="Interconnections pool",
default_prefix_type="IpamIPPrefix",
default_prefix_length=31,
@@ -1746,10 +2037,10 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
)
await management_prefix.save()
management_pool = await client.create(
- kind="CoreIPAddressPool",
+ kind=CoreIPAddressPool,
name="Management addresses pool",
default_address_type="IpamIPAddress",
- default_prefix_length=28,
+ default_prefix_length=16,
ip_namespace=default_ip_namespace,
resources=[management_prefix],
branch=branch,
@@ -1762,7 +2053,7 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
)
await external_supernet.save()
external_pool = await client.create(
- kind="CoreIPPrefixPool",
+ kind=CoreIPPrefixPool,
name="External prefixes pool",
default_prefix_type="IpamIPPrefix",
default_prefix_length=29,
@@ -1779,10 +2070,10 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
)
await ipv6_supernet_prefix.save()
ipv6_supernet_pool = await client.create(
- kind="CoreIPPrefixPool",
+ kind=CoreIPPrefixPool,
name="Internal networks pool (IPv6)",
default_prefix_type="IpamIPPrefix",
- default_prefix_length=120,
+ default_prefix_length=110,
default_member_type="address",
ip_namespace=default_ip_namespace,
resources=[ipv6_supernet_prefix],
@@ -1794,13 +2085,13 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
# Create Pool IPv6 prefixes
# ------------------------------------------
log.info("Creating pool IPv6 Prefixes and IPs")
- ipv6_internal_networks = [
- await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, branch=branch),
- await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, branch=branch),
- await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, branch=branch),
- await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, branch=branch),
- await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, branch=branch),
- await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, branch=branch),
+ ipv6_internal_networks: list[IpamIPPrefix] = [
+ await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, kind=IpamIPPrefix, branch=branch),
+ await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, kind=IpamIPPrefix, branch=branch),
+ await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, kind=IpamIPPrefix, branch=branch),
+ await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, kind=IpamIPPrefix, branch=branch),
+ await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, kind=IpamIPPrefix, branch=branch),
+ await client.allocate_next_ip_prefix(resource_pool=ipv6_supernet_pool, kind=IpamIPPrefix, branch=branch),
]
log.info("IP Prefixes Creation Completed")
@@ -1818,7 +2109,7 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
batch = await client.create_batch()
for ipv6_addr in ipv6_addresses:
obj = await client.create(
- branch=branch, kind="IpamIPAddress", address={"value": ipv6_addr, "source": account_pop.id}
+ branch=branch, kind=IpamIPAddress, address={"value": ipv6_addr, "source": account_pop.id}
)
batch.add(task=obj.save, node=obj)
@@ -1832,6 +2123,11 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
# ------------------------------------------
log.info("Creating Site and associated objects (Device, Circuit, BGP Sessions)")
sites = site_generator(nbr_site=num_sites)
+
+ # Compute the design to follow for each site
+ site_design: SiteDesign = SiteDesign(config.num_device_per_site)
+ log.info(f"following {site_design}")
+
for site in sites:
response = await generate_site(
client=client,
@@ -1842,6 +2138,7 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
loopback_pool=loopback_pool,
management_pool=management_pool,
external_pool=external_pool,
+ site_design=site_design,
)
log.info(f"{response} - Creation Completed")
@@ -1851,7 +2148,8 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
log=log,
)
- await create_bgp_mesh(client=client, branch=branch, log=log, sites=sites)
+ if config.has_bgp_mesh:
+ await create_bgp_mesh(client=client, branch=branch, log=log, sites=sites)
await create_backbone_connectivity(client=client, branch=branch, log=log, num_sites=num_sites)
@@ -1863,7 +2161,7 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
# Scenario 4 - Create some Relationship One and Attribute conflicts on a device
# Scenario 5 - Create some Node ADD and DELETE conflicts on some platform objects
# --------------------------------------------------
- if branch == "main":
+ if branch == "main" and config.has_branch:
await branch_scenario_add_upstream(site_name=sites[1].name, client=client, log=log, external_pool=external_pool)
await branch_scenario_replace_ip_addresses(
site_name=sites[2].name, client=client, log=log, interconnection_pool=interconnection_pool
@@ -1871,3 +2169,6 @@ async def run(client: InfrahubClient, log: logging.Logger, branch: str, num_site
await branch_scenario_remove_colt(site_name=sites[0].name, client=client, log=log)
await branch_scenario_conflict_device(site_name=sites[3].name, client=client, log=log)
await branch_scenario_conflict_platform(client=client, log=log)
+
+ # Stop the timer and display elapsed time
+ log.info(f"Data loaded in {round(time.time() - start)}s")
diff --git a/models/protocols.py b/models/protocols.py
new file mode 100644
index 0000000000..cce3526241
--- /dev/null
+++ b/models/protocols.py
@@ -0,0 +1,258 @@
+#
+# Generated by "infrahubctl protocols"
+#
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from infrahub_sdk.protocols import (
+ BuiltinIPAddress,
+ BuiltinIPPrefix,
+ CoreArtifactTarget,
+ CoreNode,
+)
+
+if TYPE_CHECKING:
+ from infrahub_sdk.node import RelatedNode, RelationshipManager
+ from infrahub_sdk.protocols_base import (
+ Boolean,
+ Dropdown,
+ DropdownOptional,
+ Integer,
+ IntegerOptional,
+ String,
+ StringOptional,
+ )
+
+
+class InfraEndpoint(CoreNode):
+ connected_endpoint: RelatedNode
+
+
+class OrganizationGeneric(CoreNode):
+ name: String
+ description: StringOptional
+ tags: RelationshipManager
+ asn: RelationshipManager
+
+
+class LocationGeneric(CoreNode):
+ name: String
+ description: StringOptional
+
+
+class InfraInterface(CoreNode):
+ name: String
+ description: StringOptional
+ speed: Integer
+ mtu: Integer
+ enabled: Boolean
+ status: DropdownOptional
+ role: DropdownOptional
+ device: RelatedNode
+ tags: RelationshipManager
+
+
+class InfraLagInterface(CoreNode):
+ lacp: String
+ minimum_links: Integer
+ max_bundle: IntegerOptional
+ mlag: RelatedNode
+
+
+class InfraMlagInterface(CoreNode):
+ mlag_id: Integer
+ mlag_domain: RelatedNode
+
+
+class InfraService(CoreNode):
+ name: String
+
+
+class InfraAutonomousSystem(CoreNode):
+ name: String
+ asn: Integer
+ description: StringOptional
+ organization: RelatedNode
+
+
+class InfraBGPPeerGroup(CoreNode):
+ name: String
+ description: StringOptional
+ import_policies: StringOptional
+ export_policies: StringOptional
+ local_as: RelatedNode
+ remote_as: RelatedNode
+
+
+class InfraBGPSession(CoreArtifactTarget):
+ type: String
+ description: StringOptional
+ import_policies: StringOptional
+ export_policies: StringOptional
+ status: Dropdown
+ role: Dropdown
+ local_as: RelatedNode
+ remote_as: RelatedNode
+ local_ip: RelatedNode
+ remote_ip: RelatedNode
+ device: RelatedNode
+ peer_group: RelatedNode
+ peer_session: RelatedNode
+
+
+class InfraBackBoneService(InfraService):
+ circuit_id: String
+ internal_circuit_id: String
+ provider: RelatedNode
+ site_a: RelatedNode
+ site_b: RelatedNode
+
+
+class InfraCircuit(CoreNode):
+ circuit_id: String
+ description: StringOptional
+ vendor_id: StringOptional
+ status: Dropdown
+ role: Dropdown
+ provider: RelatedNode
+ endpoints: RelationshipManager
+ bgp_sessions: RelationshipManager
+
+
+class InfraCircuitEndpoint(InfraEndpoint):
+ description: StringOptional
+ site: RelatedNode
+ circuit: RelatedNode
+
+
+class LocationContinent(LocationGeneric):
+ pass
+
+
+class LocationCountry(LocationGeneric):
+ pass
+
+
+class InfraDevice(CoreArtifactTarget):
+ name: String
+ description: StringOptional
+ type: String
+ status: DropdownOptional
+ role: DropdownOptional
+ site: RelatedNode
+ interfaces: RelationshipManager
+ asn: RelatedNode
+ tags: RelationshipManager
+ primary_address: RelatedNode
+ platform: RelatedNode
+ mlag_domain: RelatedNode
+
+
+class IpamIPAddress(BuiltinIPAddress):
+ interface: RelatedNode
+
+
+class IpamIPPrefix(BuiltinIPPrefix):
+ pass
+
+
+class InfraInterfaceL2(InfraInterface, InfraEndpoint, CoreArtifactTarget):
+ l2_mode: String
+ lacp_rate: String
+ lacp_priority: Integer
+ lag: RelatedNode
+ untagged_vlan: RelatedNode
+ tagged_vlan: RelationshipManager
+
+
+class InfraInterfaceL3(InfraInterface, InfraEndpoint, CoreArtifactTarget):
+ lacp_rate: String
+ lacp_priority: Integer
+ ip_addresses: RelationshipManager
+ lag: RelatedNode
+
+
+class InfraLagInterfaceL2(InfraInterface, InfraLagInterface, CoreArtifactTarget):
+ l2_mode: String
+ members: RelationshipManager
+ untagged_vlan: RelatedNode
+ tagged_vlan: RelationshipManager
+
+
+class InfraLagInterfaceL3(InfraInterface, InfraLagInterface, CoreArtifactTarget):
+ members: RelationshipManager
+ ip_addresses: RelationshipManager
+
+
+class OrganizationManufacturer(OrganizationGeneric):
+ platform: RelationshipManager
+
+
+class InfraMlagDomain(CoreNode):
+ name: String
+ domain_id: Integer
+ devices: RelationshipManager
+ peer_interfaces: RelationshipManager
+
+
+class InfraMlagInterfaceL2(InfraMlagInterface):
+ members: RelationshipManager
+
+
+class InfraMlagInterfaceL3(InfraMlagInterface):
+ members: RelationshipManager
+
+
+class InfraPlatform(CoreNode):
+ name: String
+ description: StringOptional
+ nornir_platform: StringOptional
+ napalm_driver: StringOptional
+ netmiko_device_type: StringOptional
+ ansible_network_os: StringOptional
+ devices: RelationshipManager
+
+
+class OrganizationProvider(OrganizationGeneric):
+ location: RelationshipManager
+ circuit: RelationshipManager
+
+
+class LocationRack(LocationGeneric):
+ name: String
+ description: StringOptional
+ height: String
+ facility_id: StringOptional
+ serial_number: StringOptional
+ asset_tag: StringOptional
+ status: Dropdown
+ role: DropdownOptional
+ site: RelatedNode
+ tags: RelationshipManager
+
+
+class LocationSite(LocationGeneric):
+ city: StringOptional
+ address: StringOptional
+ contact: StringOptional
+ devices: RelationshipManager
+ vlans: RelationshipManager
+ circuit_endpoints: RelationshipManager
+ tags: RelationshipManager
+
+
+class OrganizationTenant(OrganizationGeneric):
+ location: RelationshipManager
+ circuit: RelationshipManager
+
+
+class InfraVLAN(CoreNode):
+ name: String
+ description: StringOptional
+ vlan_id: Integer
+ status: Dropdown
+ role: Dropdown
+ site: RelatedNode
+ gateway: RelatedNode
diff --git a/package-lock.json b/package-lock.json
index 52a943ec3e..63962dcaf3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,7 +5,7 @@
"packages": {
"": {
"dependencies": {
- "markdownlint-cli2": "^0.11.0"
+ "markdownlint-cli2": "^0.14.0"
},
"devDependencies": {
"husky": "^8.0.3",
@@ -45,9 +45,9 @@
}
},
"node_modules/@sindresorhus/merge-streams": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz",
- "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
+ "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
"engines": {
"node": ">=18"
},
@@ -258,9 +258,9 @@
"dev": true
},
"node_modules/entities": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
- "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
@@ -307,9 +307,9 @@
}
},
"node_modules/fastq": {
- "version": "1.16.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz",
- "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==",
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dependencies": {
"reusify": "^1.0.4"
}
@@ -349,11 +349,11 @@
}
},
"node_modules/globby": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz",
- "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==",
+ "version": "14.0.2",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz",
+ "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==",
"dependencies": {
- "@sindresorhus/merge-streams": "^1.0.0",
+ "@sindresorhus/merge-streams": "^2.1.0",
"fast-glob": "^3.3.2",
"ignore": "^5.2.4",
"path-type": "^5.0.0",
@@ -392,9 +392,9 @@
}
},
"node_modules/ignore": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
- "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"engines": {
"node": ">= 4"
}
@@ -465,6 +465,22 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsonc-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+ "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="
+ },
"node_modules/lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -475,11 +491,11 @@
}
},
"node_modules/linkify-it": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
- "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"dependencies": {
- "uc.micro": "^1.0.1"
+ "uc.micro": "^2.0.0"
}
},
"node_modules/lint-staged": {
@@ -749,27 +765,28 @@
}
},
"node_modules/markdown-it": {
- "version": "13.0.2",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz",
- "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==",
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"dependencies": {
"argparse": "^2.0.1",
- "entities": "~3.0.1",
- "linkify-it": "^4.0.1",
- "mdurl": "^1.0.1",
- "uc.micro": "^1.0.5"
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.0",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
},
"bin": {
- "markdown-it": "bin/markdown-it.js"
+ "markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/markdownlint": {
- "version": "0.32.1",
- "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.32.1.tgz",
- "integrity": "sha512-3sx9xpi4xlHlokGyHO9k0g3gJbNY4DI6oNEeEYq5gQ4W7UkiJ90VDAnuDl2U+yyXOUa6BX+0gf69ZlTUGIBp6A==",
+ "version": "0.35.0",
+ "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.35.0.tgz",
+ "integrity": "sha512-wgp8yesWjFBL7bycA3hxwHRdsZGJhjhyP1dSxKVKrza0EPFYtn+mHtkVy6dvP1kGSjovyG5B8yNP6Frj0UFUJg==",
"dependencies": {
- "markdown-it": "13.0.2",
- "markdownlint-micromark": "0.1.7"
+ "markdown-it": "14.1.0",
+ "markdownlint-micromark": "0.1.10"
},
"engines": {
"node": ">=18"
@@ -779,21 +796,19 @@
}
},
"node_modules/markdownlint-cli2": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.11.0.tgz",
- "integrity": "sha512-RmFpr+My5in8KT+H/A6ozKIVYVzZtL5t9c8DYdv0YJdljl385z44CcCVBrclpHxCGMY2tr0hZ/ca+meGGvgdnQ==",
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.14.0.tgz",
+ "integrity": "sha512-2cqdWy56frU2FTpbuGb83mEWWYuUIYv6xS8RVEoUAuKNw/hXPar2UYGpuzUhlFMngE8Omaz4RBH52MzfRbGshw==",
"dependencies": {
- "globby": "14.0.0",
- "markdownlint": "0.32.1",
- "markdownlint-cli2-formatter-default": "0.0.4",
- "micromatch": "4.0.5",
- "strip-json-comments": "5.0.1",
- "yaml": "2.3.4"
+ "globby": "14.0.2",
+ "js-yaml": "4.1.0",
+ "jsonc-parser": "3.3.1",
+ "markdownlint": "0.35.0",
+ "markdownlint-cli2-formatter-default": "0.0.5",
+ "micromatch": "4.0.8"
},
"bin": {
- "markdownlint-cli2": "markdownlint-cli2.js",
- "markdownlint-cli2-config": "markdownlint-cli2-config.js",
- "markdownlint-cli2-fix": "markdownlint-cli2-fix.js"
+ "markdownlint-cli2": "markdownlint-cli2.js"
},
"engines": {
"node": ">=18"
@@ -803,25 +818,31 @@
}
},
"node_modules/markdownlint-cli2-formatter-default": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.4.tgz",
- "integrity": "sha512-xm2rM0E+sWgjpPn1EesPXx5hIyrN2ddUnUwnbCsD/ONxYtw3PX6LydvdH6dciWAoFDpwzbHM1TO7uHfcMd6IYg==",
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-default/-/markdownlint-cli2-formatter-default-0.0.5.tgz",
+ "integrity": "sha512-4XKTwQ5m1+Txo2kuQ3Jgpo/KmnG+X90dWt4acufg6HVGadTUG5hzHF/wssp9b5MBYOMCnZ9RMPaU//uHsszF8Q==",
+ "funding": {
+ "url": "https://github.com/sponsors/DavidAnson"
+ },
"peerDependencies": {
"markdownlint-cli2": ">=0.0.4"
}
},
"node_modules/markdownlint-micromark": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz",
- "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==",
+ "version": "0.1.10",
+ "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.10.tgz",
+ "integrity": "sha512-no5ZfdqAdWGxftCLlySHSgddEjyW4kui4z7amQcGsSKfYC5v/ou+8mIQVyg9KQMeEZLNtz9OPDTj7nnTnoR4FQ==",
"engines": {
- "node": ">=16"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/DavidAnson"
}
},
"node_modules/mdurl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
- "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="
},
"node_modules/merge-stream": {
"version": "2.0.0",
@@ -838,11 +859,11 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -985,6 +1006,14 @@
"node": ">=0.10"
}
},
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -1194,17 +1223,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/strip-json-comments": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz",
- "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==",
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -1241,9 +1259,9 @@
}
},
"node_modules/uc.micro": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
- "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="
},
"node_modules/unicorn-magic": {
"version": "0.1.0",
@@ -1357,6 +1375,7 @@
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",
"integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==",
+ "dev": true,
"engines": {
"node": ">= 14"
}
diff --git a/package.json b/package.json
index c6e150564a..8cd2e0b052 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,10 @@
{
"scripts": {
- "lint:frontend": "cd frontend/app && npm run format-code",
+ "lint:frontend": "cd frontend/app && npm run biome",
"prepare": "husky install"
},
"dependencies": {
- "markdownlint-cli2": "^0.11.0"
+ "markdownlint-cli2": "^0.14.0"
},
"devDependencies": {
"husky": "^8.0.3",
diff --git a/poetry.lock b/poetry.lock
index 6745ea2459..3d27051fca 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -30,6 +30,43 @@ files = [
pamqp = "3.3.0"
yarl = "*"
+[[package]]
+name = "aiosqlite"
+version = "0.20.0"
+description = "asyncio bridge to the standard sqlite3 module"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "aiosqlite-0.20.0-py3-none-any.whl", hash = "sha256:36a1deaca0cac40ebe32aac9977a6e2bbc7f5189f23f4a54d5908986729e5bd6"},
+ {file = "aiosqlite-0.20.0.tar.gz", hash = "sha256:6d35c8c256637f4672f843c31021464090805bf925385ac39473fb16eaaca3d7"},
+]
+
+[package.dependencies]
+typing_extensions = ">=4.0"
+
+[package.extras]
+dev = ["attribution (==1.7.0)", "black (==24.2.0)", "coverage[toml] (==7.4.1)", "flake8 (==7.0.0)", "flake8-bugbear (==24.2.6)", "flit (==3.9.0)", "mypy (==1.8.0)", "ufmt (==2.3.0)", "usort (==1.0.8.post1)"]
+docs = ["sphinx (==7.2.6)", "sphinx-mdinclude (==0.5.3)"]
+
+[[package]]
+name = "alembic"
+version = "1.13.2"
+description = "A database migration tool for SQLAlchemy."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"},
+ {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"},
+]
+
+[package.dependencies]
+Mako = "*"
+SQLAlchemy = ">=1.3.0"
+typing-extensions = ">=4"
+
+[package.extras]
+tz = ["backports.zoneinfo"]
+
[[package]]
name = "aniso8601"
version = "9.0.1"
@@ -57,13 +94,13 @@ files = [
[[package]]
name = "anyio"
-version = "4.4.0"
+version = "4.6.0"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
optional = false
-python-versions = ">=3.8"
+python-versions = ">=3.9"
files = [
- {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"},
- {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"},
+ {file = "anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a"},
+ {file = "anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb"},
]
[package.dependencies]
@@ -73,9 +110,28 @@ sniffio = ">=1.1"
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
[package.extras]
-doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
-test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
-trio = ["trio (>=0.23)"]
+doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
+test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.21.0b1)"]
+trio = ["trio (>=0.26.1)"]
+
+[[package]]
+name = "apprise"
+version = "1.9.0"
+description = "Push Notifications that work with just about every platform!"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "apprise-1.9.0-py3-none-any.whl", hash = "sha256:7192c953eeb282a7afee012512d3de0104b5a6a11bdda29283435df5a79dfe7f"},
+ {file = "apprise-1.9.0.tar.gz", hash = "sha256:b5c93afd6331afe4b63a55d1cea9076e47becb4ba89b562b181c13e25bb0c7d6"},
+]
+
+[package.dependencies]
+certifi = "*"
+click = ">=5.0"
+markdown = "*"
+PyYAML = "*"
+requests = "*"
+requests-oauthlib = "*"
[[package]]
name = "asgi-correlation-id"
@@ -94,6 +150,20 @@ starlette = ">=0.18"
[package.extras]
celery = ["celery"]
+[[package]]
+name = "asgi-lifespan"
+version = "2.1.0"
+description = "Programmatic startup/shutdown of ASGI apps."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "asgi-lifespan-2.1.0.tar.gz", hash = "sha256:5e2effaf0bfe39829cf2d64e7ecc47c7d86d676a6599f7afba378c31f5e3a308"},
+ {file = "asgi_lifespan-2.1.0-py3-none-any.whl", hash = "sha256:ed840706680e28428c01e14afb3875d7d76d3206f3d5b2f2294e059b5c23804f"},
+]
+
+[package.dependencies]
+sniffio = "*"
+
[[package]]
name = "asgiref"
version = "3.8.1"
@@ -154,6 +224,96 @@ files = [
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
]
+[[package]]
+name = "asyncpg"
+version = "0.29.0"
+description = "An asyncio PostgreSQL driver"
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "asyncpg-0.29.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72fd0ef9f00aeed37179c62282a3d14262dbbafb74ec0ba16e1b1864d8a12169"},
+ {file = "asyncpg-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52e8f8f9ff6e21f9b39ca9f8e3e33a5fcdceaf5667a8c5c32bee158e313be385"},
+ {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e6823a7012be8b68301342ba33b4740e5a166f6bbda0aee32bc01638491a22"},
+ {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:746e80d83ad5d5464cfbf94315eb6744222ab00aa4e522b704322fb182b83610"},
+ {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ff8e8109cd6a46ff852a5e6bab8b0a047d7ea42fcb7ca5ae6eaae97d8eacf397"},
+ {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97eb024685b1d7e72b1972863de527c11ff87960837919dac6e34754768098eb"},
+ {file = "asyncpg-0.29.0-cp310-cp310-win32.whl", hash = "sha256:5bbb7f2cafd8d1fa3e65431833de2642f4b2124be61a449fa064e1a08d27e449"},
+ {file = "asyncpg-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:76c3ac6530904838a4b650b2880f8e7af938ee049e769ec2fba7cd66469d7772"},
+ {file = "asyncpg-0.29.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4900ee08e85af01adb207519bb4e14b1cae8fd21e0ccf80fac6aa60b6da37b4"},
+ {file = "asyncpg-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a65c1dcd820d5aea7c7d82a3fdcb70e096f8f70d1a8bf93eb458e49bfad036ac"},
+ {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b52e46f165585fd6af4863f268566668407c76b2c72d366bb8b522fa66f1870"},
+ {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc600ee8ef3dd38b8d67421359779f8ccec30b463e7aec7ed481c8346decf99f"},
+ {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:039a261af4f38f949095e1e780bae84a25ffe3e370175193174eb08d3cecab23"},
+ {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6feaf2d8f9138d190e5ec4390c1715c3e87b37715cd69b2c3dfca616134efd2b"},
+ {file = "asyncpg-0.29.0-cp311-cp311-win32.whl", hash = "sha256:1e186427c88225ef730555f5fdda6c1812daa884064bfe6bc462fd3a71c4b675"},
+ {file = "asyncpg-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfe73ffae35f518cfd6e4e5f5abb2618ceb5ef02a2365ce64f132601000587d3"},
+ {file = "asyncpg-0.29.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6011b0dc29886ab424dc042bf9eeb507670a3b40aece3439944006aafe023178"},
+ {file = "asyncpg-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b544ffc66b039d5ec5a7454667f855f7fec08e0dfaf5a5490dfafbb7abbd2cfb"},
+ {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d84156d5fb530b06c493f9e7635aa18f518fa1d1395ef240d211cb563c4e2364"},
+ {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54858bc25b49d1114178d65a88e48ad50cb2b6f3e475caa0f0c092d5f527c106"},
+ {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bde17a1861cf10d5afce80a36fca736a86769ab3579532c03e45f83ba8a09c59"},
+ {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:37a2ec1b9ff88d8773d3eb6d3784dc7e3fee7756a5317b67f923172a4748a175"},
+ {file = "asyncpg-0.29.0-cp312-cp312-win32.whl", hash = "sha256:bb1292d9fad43112a85e98ecdc2e051602bce97c199920586be83254d9dafc02"},
+ {file = "asyncpg-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:2245be8ec5047a605e0b454c894e54bf2ec787ac04b1cb7e0d3c67aa1e32f0fe"},
+ {file = "asyncpg-0.29.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0009a300cae37b8c525e5b449233d59cd9868fd35431abc470a3e364d2b85cb9"},
+ {file = "asyncpg-0.29.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cad1324dbb33f3ca0cd2074d5114354ed3be2b94d48ddfd88af75ebda7c43cc"},
+ {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:012d01df61e009015944ac7543d6ee30c2dc1eb2f6b10b62a3f598beb6531548"},
+ {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000c996c53c04770798053e1730d34e30cb645ad95a63265aec82da9093d88e7"},
+ {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e0bfe9c4d3429706cf70d3249089de14d6a01192d617e9093a8e941fea8ee775"},
+ {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:642a36eb41b6313ffa328e8a5c5c2b5bea6ee138546c9c3cf1bffaad8ee36dd9"},
+ {file = "asyncpg-0.29.0-cp38-cp38-win32.whl", hash = "sha256:a921372bbd0aa3a5822dd0409da61b4cd50df89ae85150149f8c119f23e8c408"},
+ {file = "asyncpg-0.29.0-cp38-cp38-win_amd64.whl", hash = "sha256:103aad2b92d1506700cbf51cd8bb5441e7e72e87a7b3a2ca4e32c840f051a6a3"},
+ {file = "asyncpg-0.29.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5340dd515d7e52f4c11ada32171d87c05570479dc01dc66d03ee3e150fb695da"},
+ {file = "asyncpg-0.29.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e17b52c6cf83e170d3d865571ba574577ab8e533e7361a2b8ce6157d02c665d3"},
+ {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f100d23f273555f4b19b74a96840aa27b85e99ba4b1f18d4ebff0734e78dc090"},
+ {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48e7c58b516057126b363cec8ca02b804644fd012ef8e6c7e23386b7d5e6ce83"},
+ {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f9ea3f24eb4c49a615573724d88a48bd1b7821c890c2effe04f05382ed9e8810"},
+ {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8d36c7f14a22ec9e928f15f92a48207546ffe68bc412f3be718eedccdf10dc5c"},
+ {file = "asyncpg-0.29.0-cp39-cp39-win32.whl", hash = "sha256:797ab8123ebaed304a1fad4d7576d5376c3a006a4100380fb9d517f0b59c1ab2"},
+ {file = "asyncpg-0.29.0-cp39-cp39-win_amd64.whl", hash = "sha256:cce08a178858b426ae1aa8409b5cc171def45d4293626e7aa6510696d46decd8"},
+ {file = "asyncpg-0.29.0.tar.gz", hash = "sha256:d1c49e1f44fffafd9a55e1a9b101590859d881d639ea2922516f5d9c512d354e"},
+]
+
+[package.dependencies]
+async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.12.0\""}
+
+[package.extras]
+docs = ["Sphinx (>=5.3.0,<5.4.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"]
+test = ["flake8 (>=6.1,<7.0)", "uvloop (>=0.15.3)"]
+
+[[package]]
+name = "attrs"
+version = "24.2.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
+ {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
+]
+
+[package.extras]
+benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
+tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
+
+[[package]]
+name = "authlib"
+version = "1.3.2"
+description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Authlib-1.3.2-py2.py3-none-any.whl", hash = "sha256:ede026a95e9f5cdc2d4364a52103f5405e75aa156357e831ef2bfd0bc5094dfc"},
+ {file = "authlib-1.3.2.tar.gz", hash = "sha256:4b16130117f9eb82aa6eec97f6dd4673c3f960ac0283ccdae2897ee4bc030ba2"},
+]
+
+[package.dependencies]
+cryptography = "*"
+
[[package]]
name = "bcrypt"
version = "4.1.3"
@@ -335,6 +495,17 @@ files = [
{file = "Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724"},
]
+[[package]]
+name = "cachetools"
+version = "5.5.0"
+description = "Extensible memoizing collections and decorators"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"},
+ {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"},
+]
+
[[package]]
name = "certifi"
version = "2024.8.30"
@@ -549,6 +720,17 @@ files = [
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
+[[package]]
+name = "cloudpickle"
+version = "3.0.0"
+description = "Pickler class to extend the standard pickle.Pickler functionality"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7"},
+ {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"},
+]
+
[[package]]
name = "colorama"
version = "0.4.6"
@@ -659,6 +841,17 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pil
test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"]
+[[package]]
+name = "coolname"
+version = "2.2.0"
+description = "Random name and slug generator"
+optional = false
+python-versions = "*"
+files = [
+ {file = "coolname-2.2.0-py2.py3-none-any.whl", hash = "sha256:4d1563186cfaf71b394d5df4c744f8c41303b6846413645e31d31915cdeb13e8"},
+ {file = "coolname-2.2.0.tar.gz", hash = "sha256:6c5d5731759104479e7ca195a9b64f7900ac5bead40183c09323c7d0be9e75c7"},
+]
+
[[package]]
name = "coverage"
version = "7.6.1"
@@ -746,6 +939,70 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1
[package.extras]
toml = ["tomli"]
+[[package]]
+name = "croniter"
+version = "3.0.3"
+description = "croniter provides iteration for datetime object with cron like format"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.6"
+files = [
+ {file = "croniter-3.0.3-py2.py3-none-any.whl", hash = "sha256:b3bd11f270dc54ccd1f2397b813436015a86d30ffc5a7a9438eec1ed916f2101"},
+ {file = "croniter-3.0.3.tar.gz", hash = "sha256:34117ec1741f10a7bd0ec3ad7d8f0eb8fa457a2feb9be32e6a2250e158957668"},
+]
+
+[package.dependencies]
+python-dateutil = "*"
+pytz = ">2021.1"
+
+[[package]]
+name = "cryptography"
+version = "43.0.1"
+description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
+ {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
+ {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
+ {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
+ {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
+ {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
+ {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
+ {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
+ {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
+ {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
+ {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
+ {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
+ {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
+ {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
+ {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
+]
+
+[package.dependencies]
+cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
+
+[package.extras]
+docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
+docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
+nox = ["nox"]
+pep8test = ["check-sdist", "click", "mypy", "ruff"]
+sdist = ["build"]
+ssh = ["bcrypt (>=3.1.5)"]
+test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test-randomorder = ["pytest-randomly"]
+
[[package]]
name = "cycler"
version = "0.12.1"
@@ -761,6 +1018,28 @@ files = [
docs = ["ipython", "matplotlib", "numpydoc", "sphinx"]
tests = ["pytest", "pytest-cov", "pytest-xdist"]
+[[package]]
+name = "dateparser"
+version = "1.2.0"
+description = "Date parsing library designed to parse dates from HTML pages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "dateparser-1.2.0-py2.py3-none-any.whl", hash = "sha256:0b21ad96534e562920a0083e97fd45fa959882d4162acc358705144520a35830"},
+ {file = "dateparser-1.2.0.tar.gz", hash = "sha256:7975b43a4222283e0ae15be7b4999d08c9a70e2d378ac87385b1ccf2cffbbb30"},
+]
+
+[package.dependencies]
+python-dateutil = "*"
+pytz = "*"
+regex = "<2019.02.19 || >2019.02.19,<2021.8.27 || >2021.8.27"
+tzlocal = "*"
+
+[package.extras]
+calendars = ["convertdate", "hijri-converter"]
+fasttext = ["fasttext"]
+langdetect = ["langdetect"]
+
[[package]]
name = "decorator"
version = "5.1.1"
@@ -934,13 +1213,13 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth
[[package]]
name = "faker"
-version = "28.4.1"
+version = "29.0.0"
description = "Faker is a Python package that generates fake data for you."
optional = false
python-versions = ">=3.8"
files = [
- {file = "Faker-28.4.1-py3-none-any.whl", hash = "sha256:e59c01d1e8b8e20a83255ab8232c143cb2af3b4f5ab6a3f5ce495f385ad8ab4c"},
- {file = "faker-28.4.1.tar.gz", hash = "sha256:4294d169255a045990720d6f3fa4134b764a4cdf46ef0d3c7553d2506f1adaa1"},
+ {file = "Faker-29.0.0-py3-none-any.whl", hash = "sha256:32d0ee7d42925ff06e4a7d906ee7efbf34f5052a41a2a1eb8bb174a422a5498f"},
+ {file = "faker-29.0.0.tar.gz", hash = "sha256:34e89aec594cad9773431ca479ee95c7ce03dd9f22fda2524e2373b880a2fa77"},
]
[package.dependencies]
@@ -985,18 +1264,18 @@ full = ["peewee (>=3)", "pillow (>=9.4,<10.0)", "sqlalchemy (>=1.4)"]
[[package]]
name = "filelock"
-version = "3.16.0"
+version = "3.16.1"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.8"
files = [
- {file = "filelock-3.16.0-py3-none-any.whl", hash = "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609"},
- {file = "filelock-3.16.0.tar.gz", hash = "sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec"},
+ {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
+ {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
]
[package.extras]
-docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.1.1)", "pytest (>=8.3.2)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.3)"]
+docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"]
typing = ["typing-extensions (>=4.12.2)"]
[[package]]
@@ -1115,6 +1394,45 @@ ufo = ["fs (>=2.2.0,<3)"]
unicode = ["unicodedata2 (>=15.1.0)"]
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
+[[package]]
+name = "fsspec"
+version = "2024.9.0"
+description = "File-system specification"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "fsspec-2024.9.0-py3-none-any.whl", hash = "sha256:a0947d552d8a6efa72cc2c730b12c41d043509156966cca4fb157b0f2a0c574b"},
+ {file = "fsspec-2024.9.0.tar.gz", hash = "sha256:4b0afb90c2f21832df142f292649035d80b421f60a9e1c027802e5a0da2b04e8"},
+]
+
+[package.extras]
+abfs = ["adlfs"]
+adl = ["adlfs"]
+arrow = ["pyarrow (>=1)"]
+dask = ["dask", "distributed"]
+dev = ["pre-commit", "ruff"]
+doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"]
+dropbox = ["dropbox", "dropboxdrivefs", "requests"]
+full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"]
+fuse = ["fusepy"]
+gcs = ["gcsfs"]
+git = ["pygit2"]
+github = ["requests"]
+gs = ["gcsfs"]
+gui = ["panel"]
+hdfs = ["pyarrow (>=1)"]
+http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"]
+libarchive = ["libarchive-c"]
+oci = ["ocifs"]
+s3 = ["s3fs"]
+sftp = ["paramiko"]
+smb = ["smbprotocol"]
+ssh = ["paramiko"]
+test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"]
+test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask-expr", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"]
+test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"]
+tqdm = ["tqdm"]
+
[[package]]
name = "gevent"
version = "24.2.1"
@@ -1358,77 +1676,122 @@ files = [
[package.dependencies]
graphql-core = ">=3.2,<3.3"
+[[package]]
+name = "graphviz"
+version = "0.20.3"
+description = "Simple Python interface for Graphviz"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "graphviz-0.20.3-py3-none-any.whl", hash = "sha256:81f848f2904515d8cd359cc611faba817598d2feaac4027b266aa3eda7b3dde5"},
+ {file = "graphviz-0.20.3.zip", hash = "sha256:09d6bc81e6a9fa392e7ba52135a9d49f1ed62526f96499325930e87ca1b5925d"},
+]
+
+[package.extras]
+dev = ["flake8", "pep8-naming", "tox (>=3)", "twine", "wheel"]
+docs = ["sphinx (>=5,<7)", "sphinx-autodoc-typehints", "sphinx-rtd-theme"]
+test = ["coverage", "pytest (>=7,<8.1)", "pytest-cov", "pytest-mock (>=3)"]
+
[[package]]
name = "greenlet"
-version = "3.0.3"
+version = "3.1.1"
description = "Lightweight in-process concurrent programming"
optional = false
python-versions = ">=3.7"
files = [
- {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"},
- {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"},
- {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"},
- {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"},
- {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"},
- {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"},
- {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"},
- {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"},
- {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"},
- {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"},
- {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"},
- {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"},
- {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"},
- {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"},
- {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"},
- {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"},
- {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"},
- {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"},
- {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"},
- {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"},
- {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"},
- {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"},
- {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"},
- {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"},
- {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"},
- {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"},
- {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"},
- {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"},
- {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"},
- {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"},
- {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"},
- {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"},
- {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"},
- {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"},
+ {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"},
+ {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"},
+ {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"},
+ {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"},
+ {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"},
+ {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"},
+ {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"},
+ {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"},
+ {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"},
+ {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"},
+ {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"},
+ {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"},
+ {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"},
+ {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"},
+ {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"},
+ {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"},
+ {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"},
+ {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"},
+ {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"},
+ {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"},
+ {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"},
+ {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"},
+ {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"},
+ {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"},
+ {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"},
+ {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"},
+ {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"},
+ {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"},
+ {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"},
+ {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"},
+ {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"},
+ {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"},
+ {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"},
+ {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"},
+ {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"},
+ {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"},
+ {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"},
+ {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"},
+ {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"},
+ {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"},
+ {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"},
]
[package.extras]
docs = ["Sphinx", "furo"]
test = ["objgraph", "psutil"]
+[[package]]
+name = "griffe"
+version = "1.3.1"
+description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "griffe-1.3.1-py3-none-any.whl", hash = "sha256:940aeb630bc3054b4369567f150b6365be6f11eef46b0ed8623aea96e6d17b19"},
+ {file = "griffe-1.3.1.tar.gz", hash = "sha256:3f86a716b631a4c0f96a43cb75d05d3c85975003c20540426c0eba3b0581c56a"},
+]
+
+[package.dependencies]
+colorama = ">=0.4"
+
[[package]]
name = "grpcio"
version = "1.66.1"
@@ -1519,6 +1882,21 @@ files = [
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
+[[package]]
+name = "h2"
+version = "4.1.0"
+description = "HTTP/2 State-Machine based protocol implementation"
+optional = false
+python-versions = ">=3.6.1"
+files = [
+ {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"},
+ {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"},
+]
+
+[package.dependencies]
+hpack = ">=4.0,<5"
+hyperframe = ">=6.0,<7"
+
[[package]]
name = "hiredis"
version = "3.0.0"
@@ -1622,6 +2000,17 @@ files = [
{file = "hiredis-3.0.0.tar.gz", hash = "sha256:fed8581ae26345dea1f1e0d1a96e05041a727a45e7d8d459164583e23c6ac441"},
]
+[[package]]
+name = "hpack"
+version = "4.0.0"
+description = "Pure-Python HPACK header compression"
+optional = false
+python-versions = ">=3.6.1"
+files = [
+ {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"},
+ {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"},
+]
+
[[package]]
name = "httpcore"
version = "1.0.5"
@@ -1705,6 +2094,7 @@ files = [
[package.dependencies]
anyio = "*"
certifi = "*"
+h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""}
httpcore = "==1.*"
idna = "*"
sniffio = "*"
@@ -1716,15 +2106,40 @@ http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
zstd = ["zstandard (>=0.18.0)"]
+[[package]]
+name = "humanize"
+version = "4.10.0"
+description = "Python humanize utilities"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "humanize-4.10.0-py3-none-any.whl", hash = "sha256:39e7ccb96923e732b5c2e27aeaa3b10a8dfeeba3eb965ba7b74a3eb0e30040a6"},
+ {file = "humanize-4.10.0.tar.gz", hash = "sha256:06b6eb0293e4b85e8d385397c5868926820db32b9b654b932f57fa41c23c9978"},
+]
+
+[package.extras]
+tests = ["freezegun", "pytest", "pytest-cov"]
+
+[[package]]
+name = "hyperframe"
+version = "6.0.1"
+description = "HTTP/2 framing layer for Python"
+optional = false
+python-versions = ">=3.6.1"
+files = [
+ {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"},
+ {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"},
+]
+
[[package]]
name = "identify"
-version = "2.6.0"
+version = "2.6.1"
description = "File identification library for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"},
- {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"},
+ {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"},
+ {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"},
]
[package.extras]
@@ -1732,15 +2147,18 @@ license = ["ukkonen"]
[[package]]
name = "idna"
-version = "3.8"
+version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
files = [
- {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"},
- {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"},
+ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
+ {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
]
+[package.extras]
+all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
+
[[package]]
name = "importlib-metadata"
version = "7.0.0"
@@ -1762,7 +2180,7 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs
[[package]]
name = "infrahub-sdk"
-version = "0.13.1-dev0"
+version = "0.14.0-dev0"
description = "Python Client to interact with Infrahub"
optional = false
python-versions = "^3.9"
@@ -1925,6 +2343,21 @@ MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
+[[package]]
+name = "jinja2-humanize-extension"
+version = "0.4.0"
+description = "a jinja2 extension to use humanize library inside jinja2 templates"
+optional = false
+python-versions = ">=3.0"
+files = [
+ {file = "jinja2_humanize_extension-0.4.0-py3-none-any.whl", hash = "sha256:b6326e2da0f7d425338bebf58848e830421defbce785f12ae812e65128518156"},
+ {file = "jinja2_humanize_extension-0.4.0.tar.gz", hash = "sha256:e7d69b1c20f32815bbec722330ee8af14b1287bb1c2b0afa590dbf031cadeaa0"},
+]
+
+[package.dependencies]
+humanize = ">=3.14.0"
+jinja2 = "*"
+
[[package]]
name = "jmespath"
version = "1.0.1"
@@ -1936,6 +2369,66 @@ files = [
{file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"},
]
+[[package]]
+name = "jsonpatch"
+version = "1.33"
+description = "Apply JSON-Patches (RFC 6902)"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
+files = [
+ {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"},
+ {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"},
+]
+
+[package.dependencies]
+jsonpointer = ">=1.9"
+
+[[package]]
+name = "jsonpointer"
+version = "3.0.0"
+description = "Identify specific nodes in a JSON document (RFC 6901)"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"},
+ {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"},
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.23.0"
+description = "An implementation of JSON Schema validation for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"},
+ {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+jsonschema-specifications = ">=2023.03.6"
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
+
+[package.extras]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2023.12.1"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"},
+ {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"},
+]
+
+[package.dependencies]
+referencing = ">=0.31.0"
+
[[package]]
name = "kiwisolver"
version = "1.4.7"
@@ -2061,13 +2554,13 @@ files = [
[[package]]
name = "locust"
-version = "2.31.5"
+version = "2.31.6"
description = "Developer-friendly load testing framework"
optional = false
python-versions = ">=3.9"
files = [
- {file = "locust-2.31.5-py3-none-any.whl", hash = "sha256:2904ff6307d54d3202c9ebd776f9170214f6dfbe4059504dad9e3ffaca03f600"},
- {file = "locust-2.31.5.tar.gz", hash = "sha256:14b2fa6f95bf248668e6dc92d100a44f06c5dcb1c26f88a5442bcaaee18faceb"},
+ {file = "locust-2.31.6-py3-none-any.whl", hash = "sha256:004c963c7a588dc15d57d710cdc6a262d85b57936d7fad3c38ac0657aa98fc3b"},
+ {file = "locust-2.31.6.tar.gz", hash = "sha256:03b6da0491d6a0b905692d9ac128d9deec403f40dc605c481a90dbab5126318c"},
]
[package.dependencies]
@@ -2107,6 +2600,40 @@ languages = ["nltk"]
local = ["black", "build", "flake8", "hatch-fancy-pypi-readme", "ipython", "mypy", "pdbpp", "pytest-benchmark", "twine", "wheel"]
tests = ["coverage", "lunr[languages]", "pytest", "pytest-timeout", "tox"]
+[[package]]
+name = "mako"
+version = "1.3.5"
+description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"},
+ {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=0.9.2"
+
+[package.extras]
+babel = ["Babel"]
+lingua = ["lingua"]
+testing = ["pytest"]
+
+[[package]]
+name = "markdown"
+version = "3.7"
+description = "Python implementation of John Gruber's Markdown."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"},
+ {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"},
+]
+
+[package.extras]
+docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
+testing = ["coverage", "pyyaml"]
+
[[package]]
name = "markdown-it-py"
version = "3.0.0"
@@ -2301,168 +2828,181 @@ files = [
[[package]]
name = "msgpack"
-version = "1.0.8"
+version = "1.1.0"
description = "MessagePack serializer"
optional = false
python-versions = ">=3.8"
files = [
- {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"},
- {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"},
- {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"},
- {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"},
- {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"},
- {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"},
- {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"},
- {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"},
- {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"},
- {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"},
- {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"},
- {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"},
- {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"},
- {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"},
- {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"},
- {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"},
- {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"},
- {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"},
- {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"},
- {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"},
- {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"},
- {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"},
- {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"},
- {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"},
- {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"},
- {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"},
- {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"},
- {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"},
- {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"},
- {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"},
- {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"},
- {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"},
- {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"},
- {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"},
- {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"},
- {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"},
- {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"},
- {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"},
- {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"},
- {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"},
- {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"},
- {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"},
- {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"},
- {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"},
- {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"},
- {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"},
- {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"},
- {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"},
- {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"},
- {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"},
- {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"},
- {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"},
- {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"},
- {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"},
- {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"},
- {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"},
+ {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"},
+ {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"},
+ {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"},
+ {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"},
+ {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"},
+ {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"},
+ {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"},
+ {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"},
+ {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"},
+ {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"},
+ {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"},
+ {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"},
+ {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"},
+ {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"},
+ {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"},
+ {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"},
+ {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"},
+ {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"},
+ {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"},
+ {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"},
+ {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"},
+ {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"},
+ {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"},
+ {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"},
+ {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"},
+ {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"},
+ {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"},
+ {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"},
+ {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"},
+ {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"},
+ {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"},
+ {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"},
+ {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"},
+ {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"},
+ {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"},
+ {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"},
+ {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"},
+ {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"},
+ {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"},
+ {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"},
+ {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"},
+ {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"},
+ {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"},
+ {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"},
+ {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"},
+ {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"},
+ {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"},
+ {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"},
+ {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"},
+ {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"},
+ {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"},
+ {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"},
+ {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"},
+ {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"},
+ {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"},
+ {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"},
+ {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"},
+ {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"},
+ {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"},
+ {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"},
+ {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"},
+ {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"},
+ {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"},
+ {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"},
]
[[package]]
name = "multidict"
-version = "6.0.5"
+version = "6.1.0"
description = "multidict implementation"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"},
- {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"},
- {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"},
- {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"},
- {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"},
- {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"},
- {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"},
- {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"},
- {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"},
- {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"},
- {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"},
- {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"},
- {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"},
- {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"},
- {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"},
- {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"},
- {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"},
- {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"},
- {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"},
- {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"},
- {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"},
- {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"},
- {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"},
- {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"},
- {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"},
- {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"},
- {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"},
- {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"},
- {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"},
- {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"},
- {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"},
- {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"},
- {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"},
- {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"},
- {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"},
- {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"},
- {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"},
- {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"},
- {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"},
- {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"},
- {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"},
- {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"},
- {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"},
- {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"},
- {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"},
- {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"},
- {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"},
- {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"},
- {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"},
- {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"},
- {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"},
- {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"},
- {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"},
- {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"},
- {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"},
- {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"},
- {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"},
- {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"},
- {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"},
- {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"},
- {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"},
- {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"},
- {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"},
- {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"},
- {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"},
- {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"},
- {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"},
- {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"},
- {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"},
- {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"},
- {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"},
- {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"},
- {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"},
- {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"},
- {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"},
- {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"},
- {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"},
- {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"},
- {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"},
- {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"},
- {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"},
- {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"},
- {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"},
- {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"},
- {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"},
- {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"},
- {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"},
- {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"},
- {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"},
- {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
+ {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"},
+ {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"},
+ {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"},
+ {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"},
+ {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"},
+ {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"},
+ {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"},
+ {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"},
+ {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"},
+ {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"},
+ {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"},
+ {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"},
+ {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"},
+ {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"},
+ {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"},
+ {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"},
+ {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"},
+ {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"},
+ {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"},
+ {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"},
+ {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"},
+ {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"},
+ {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"},
+ {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"},
+ {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"},
+ {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"},
+ {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"},
+ {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"},
+ {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"},
+ {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"},
+ {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"},
+ {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"},
+ {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"},
+ {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"},
+ {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"},
+ {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"},
+ {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"},
+ {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"},
+ {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"},
+ {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"},
+ {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"},
+ {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"},
+ {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"},
+ {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"},
+ {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"},
+ {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"},
+ {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"},
+ {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"},
+ {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"},
+ {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"},
+ {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"},
+ {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"},
+ {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"},
+ {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"},
+ {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"},
+ {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"},
+ {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"},
+ {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"},
+ {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"},
+ {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"},
+ {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"},
+ {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"},
+ {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"},
+ {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"},
+ {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"},
+ {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"},
+ {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"},
+ {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"},
+ {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"},
+ {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"},
+ {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"},
+ {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"},
+ {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"},
+ {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"},
+ {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"},
+ {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"},
+ {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"},
+ {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"},
+ {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"},
+ {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"},
+ {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"},
+ {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"},
+ {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"},
+ {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"},
+ {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"},
+ {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"},
+ {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"},
+ {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"},
+ {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"},
+ {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"},
+ {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"},
+ {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"},
]
+[package.dependencies]
+typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""}
+
[[package]]
name = "mypy"
version = "1.11.2"
@@ -2691,6 +3231,22 @@ files = [
{file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
]
+[[package]]
+name = "oauthlib"
+version = "3.2.2"
+description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"},
+ {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"},
+]
+
+[package.extras]
+rsa = ["cryptography (>=3.0.0)"]
+signals = ["blinker (>=1.4.0)"]
+signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
+
[[package]]
name = "opentelemetry-api"
version = "1.24.0"
@@ -2906,6 +3462,72 @@ files = [
[package.extras]
dev = ["black", "mypy", "pytest"]
+[[package]]
+name = "orjson"
+version = "3.10.7"
+description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "orjson-3.10.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:74f4544f5a6405b90da8ea724d15ac9c36da4d72a738c64685003337401f5c12"},
+ {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34a566f22c28222b08875b18b0dfbf8a947e69df21a9ed5c51a6bf91cfb944ac"},
+ {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf6ba8ebc8ef5792e2337fb0419f8009729335bb400ece005606336b7fd7bab7"},
+ {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac7cf6222b29fbda9e3a472b41e6a5538b48f2c8f99261eecd60aafbdb60690c"},
+ {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de817e2f5fc75a9e7dd350c4b0f54617b280e26d1631811a43e7e968fa71e3e9"},
+ {file = "orjson-3.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:348bdd16b32556cf8d7257b17cf2bdb7ab7976af4af41ebe79f9796c218f7e91"},
+ {file = "orjson-3.10.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:479fd0844ddc3ca77e0fd99644c7fe2de8e8be1efcd57705b5c92e5186e8a250"},
+ {file = "orjson-3.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fdf5197a21dd660cf19dfd2a3ce79574588f8f5e2dbf21bda9ee2d2b46924d84"},
+ {file = "orjson-3.10.7-cp310-none-win32.whl", hash = "sha256:d374d36726746c81a49f3ff8daa2898dccab6596864ebe43d50733275c629175"},
+ {file = "orjson-3.10.7-cp310-none-win_amd64.whl", hash = "sha256:cb61938aec8b0ffb6eef484d480188a1777e67b05d58e41b435c74b9d84e0b9c"},
+ {file = "orjson-3.10.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7db8539039698ddfb9a524b4dd19508256107568cdad24f3682d5773e60504a2"},
+ {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:480f455222cb7a1dea35c57a67578848537d2602b46c464472c995297117fa09"},
+ {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8a9c9b168b3a19e37fe2778c0003359f07822c90fdff8f98d9d2a91b3144d8e0"},
+ {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8de062de550f63185e4c1c54151bdddfc5625e37daf0aa1e75d2a1293e3b7d9a"},
+ {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6b0dd04483499d1de9c8f6203f8975caf17a6000b9c0c54630cef02e44ee624e"},
+ {file = "orjson-3.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b58d3795dafa334fc8fd46f7c5dc013e6ad06fd5b9a4cc98cb1456e7d3558bd6"},
+ {file = "orjson-3.10.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:33cfb96c24034a878d83d1a9415799a73dc77480e6c40417e5dda0710d559ee6"},
+ {file = "orjson-3.10.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e724cebe1fadc2b23c6f7415bad5ee6239e00a69f30ee423f319c6af70e2a5c0"},
+ {file = "orjson-3.10.7-cp311-none-win32.whl", hash = "sha256:82763b46053727a7168d29c772ed5c870fdae2f61aa8a25994c7984a19b1021f"},
+ {file = "orjson-3.10.7-cp311-none-win_amd64.whl", hash = "sha256:eb8d384a24778abf29afb8e41d68fdd9a156cf6e5390c04cc07bbc24b89e98b5"},
+ {file = "orjson-3.10.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:44a96f2d4c3af51bfac6bc4ef7b182aa33f2f054fd7f34cc0ee9a320d051d41f"},
+ {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ac14cd57df0572453543f8f2575e2d01ae9e790c21f57627803f5e79b0d3c3"},
+ {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bdbb61dcc365dd9be94e8f7df91975edc9364d6a78c8f7adb69c1cdff318ec93"},
+ {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b48b3db6bb6e0a08fa8c83b47bc169623f801e5cc4f24442ab2b6617da3b5313"},
+ {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23820a1563a1d386414fef15c249040042b8e5d07b40ab3fe3efbfbbcbcb8864"},
+ {file = "orjson-3.10.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0c6a008e91d10a2564edbb6ee5069a9e66df3fbe11c9a005cb411f441fd2c09"},
+ {file = "orjson-3.10.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d352ee8ac1926d6193f602cbe36b1643bbd1bbcb25e3c1a657a4390f3000c9a5"},
+ {file = "orjson-3.10.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2d9f990623f15c0ae7ac608103c33dfe1486d2ed974ac3f40b693bad1a22a7b"},
+ {file = "orjson-3.10.7-cp312-none-win32.whl", hash = "sha256:7c4c17f8157bd520cdb7195f75ddbd31671997cbe10aee559c2d613592e7d7eb"},
+ {file = "orjson-3.10.7-cp312-none-win_amd64.whl", hash = "sha256:1d9c0e733e02ada3ed6098a10a8ee0052dd55774de3d9110d29868d24b17faa1"},
+ {file = "orjson-3.10.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:77d325ed866876c0fa6492598ec01fe30e803272a6e8b10e992288b009cbe149"},
+ {file = "orjson-3.10.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ea2c232deedcb605e853ae1db2cc94f7390ac776743b699b50b071b02bea6fe"},
+ {file = "orjson-3.10.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3dcfbede6737fdbef3ce9c37af3fb6142e8e1ebc10336daa05872bfb1d87839c"},
+ {file = "orjson-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11748c135f281203f4ee695b7f80bb1358a82a63905f9f0b794769483ea854ad"},
+ {file = "orjson-3.10.7-cp313-none-win32.whl", hash = "sha256:a7e19150d215c7a13f39eb787d84db274298d3f83d85463e61d277bbd7f401d2"},
+ {file = "orjson-3.10.7-cp313-none-win_amd64.whl", hash = "sha256:eef44224729e9525d5261cc8d28d6b11cafc90e6bd0be2157bde69a52ec83024"},
+ {file = "orjson-3.10.7-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6ea2b2258eff652c82652d5e0f02bd5e0463a6a52abb78e49ac288827aaa1469"},
+ {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:430ee4d85841e1483d487e7b81401785a5dfd69db5de01314538f31f8fbf7ee1"},
+ {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4b6146e439af4c2472c56f8540d799a67a81226e11992008cb47e1267a9b3225"},
+ {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:084e537806b458911137f76097e53ce7bf5806dda33ddf6aaa66a028f8d43a23"},
+ {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829cf2195838e3f93b70fd3b4292156fc5e097aac3739859ac0dcc722b27ac0"},
+ {file = "orjson-3.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1193b2416cbad1a769f868b1749535d5da47626ac29445803dae7cc64b3f5c98"},
+ {file = "orjson-3.10.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4e6c3da13e5a57e4b3dca2de059f243ebec705857522f188f0180ae88badd354"},
+ {file = "orjson-3.10.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c31008598424dfbe52ce8c5b47e0752dca918a4fdc4a2a32004efd9fab41d866"},
+ {file = "orjson-3.10.7-cp38-none-win32.whl", hash = "sha256:7122a99831f9e7fe977dc45784d3b2edc821c172d545e6420c375e5a935f5a1c"},
+ {file = "orjson-3.10.7-cp38-none-win_amd64.whl", hash = "sha256:a763bc0e58504cc803739e7df040685816145a6f3c8a589787084b54ebc9f16e"},
+ {file = "orjson-3.10.7-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e76be12658a6fa376fcd331b1ea4e58f5a06fd0220653450f0d415b8fd0fbe20"},
+ {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed350d6978d28b92939bfeb1a0570c523f6170efc3f0a0ef1f1df287cd4f4960"},
+ {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:144888c76f8520e39bfa121b31fd637e18d4cc2f115727865fdf9fa325b10412"},
+ {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09b2d92fd95ad2402188cf51573acde57eb269eddabaa60f69ea0d733e789fe9"},
+ {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b24a579123fa884f3a3caadaed7b75eb5715ee2b17ab5c66ac97d29b18fe57f"},
+ {file = "orjson-3.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591bcfe7512353bd609875ab38050efe3d55e18934e2f18950c108334b4ff"},
+ {file = "orjson-3.10.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f4db56635b58cd1a200b0a23744ff44206ee6aa428185e2b6c4a65b3197abdcd"},
+ {file = "orjson-3.10.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0fa5886854673222618638c6df7718ea7fe2f3f2384c452c9ccedc70b4a510a5"},
+ {file = "orjson-3.10.7-cp39-none-win32.whl", hash = "sha256:8272527d08450ab16eb405f47e0f4ef0e5ff5981c3d82afe0efd25dcbef2bcd2"},
+ {file = "orjson-3.10.7-cp39-none-win_amd64.whl", hash = "sha256:974683d4618c0c7dbf4f69c95a979734bf183d0658611760017f6e70a145af58"},
+ {file = "orjson-3.10.7.tar.gz", hash = "sha256:75ef0640403f945f3a1f9f6400686560dbfb0fb5b16589ad62cd477043c4eee3"},
+]
+
[[package]]
name = "packaging"
version = "24.1"
@@ -2934,40 +3556,53 @@ testing = ["coverage", "flake8", "flake8-comprehensions", "flake8-deprecated", "
[[package]]
name = "pandas"
-version = "2.2.2"
+version = "2.2.3"
description = "Powerful data structures for data analysis, time series, and statistics"
optional = false
python-versions = ">=3.9"
files = [
- {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"},
- {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"},
- {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"},
- {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"},
- {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"},
- {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"},
- {file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"},
- {file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"},
- {file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"},
- {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"},
- {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"},
- {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"},
- {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"},
- {file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"},
- {file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"},
- {file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"},
- {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"},
- {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"},
- {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"},
- {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"},
- {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"},
- {file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"},
- {file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"},
- {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"},
- {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"},
- {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"},
- {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"},
- {file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"},
- {file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"},
+ {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"},
+ {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"},
+ {file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"},
+ {file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"},
+ {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"},
+ {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"},
+ {file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"},
+ {file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"},
+ {file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"},
+ {file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"},
+ {file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"},
+ {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"},
+ {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"},
+ {file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"},
+ {file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"},
+ {file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"},
+ {file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"},
+ {file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"},
+ {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"},
+ {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"},
+ {file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"},
+ {file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"},
+ {file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"},
+ {file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"},
+ {file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"},
+ {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"},
+ {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"},
+ {file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"},
+ {file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"},
+ {file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"},
+ {file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"},
+ {file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"},
+ {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"},
+ {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"},
+ {file = "pandas-2.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39"},
+ {file = "pandas-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30"},
+ {file = "pandas-2.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c"},
+ {file = "pandas-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c"},
+ {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea"},
+ {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761"},
+ {file = "pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e"},
+ {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"},
]
[package.dependencies]
@@ -3243,13 +3878,13 @@ xmp = ["defusedxml"]
[[package]]
name = "platformdirs"
-version = "4.3.2"
+version = "4.3.6"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.8"
files = [
- {file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"},
- {file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"},
+ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
+ {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
]
[package.extras]
@@ -3274,13 +3909,13 @@ testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "polyfactory"
-version = "2.16.2"
+version = "2.17.0"
description = "Mock data generation factories"
optional = false
python-versions = "<4.0,>=3.8"
files = [
- {file = "polyfactory-2.16.2-py3-none-any.whl", hash = "sha256:e5eaf97358fee07d0d8de86a93e81dc56e3be1e1514d145fea6c5f486cda6ea1"},
- {file = "polyfactory-2.16.2.tar.gz", hash = "sha256:6d0d90deb85e5bb1733ea8744c2d44eea2b31656e11b4fa73832d2e2ab5422da"},
+ {file = "polyfactory-2.17.0-py3-none-any.whl", hash = "sha256:71b677c17bb7cebad9a5631b1aca7718280bdcedc1c25278253717882d1ac294"},
+ {file = "polyfactory-2.17.0.tar.gz", hash = "sha256:099d86f7c79c51a2caaf7c8598cc56e7b0a57c11b5918ddf699e82380735b6b7"},
]
[package.dependencies]
@@ -3325,15 +3960,100 @@ nodeenv = ">=0.11.1"
pyyaml = ">=5.1"
virtualenv = ">=20.10.0"
+[[package]]
+name = "prefect"
+version = "3.0.3"
+description = "Workflow orchestration and management."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "prefect-3.0.3-py3-none-any.whl", hash = "sha256:3291a5e687ff968249ab8996702cbf07f665b96cc1b9b996dc4dfc975810a5bd"},
+ {file = "prefect-3.0.3.tar.gz", hash = "sha256:69759beb93f974467f13df9e31ff047b77c71b1dab5869ed67207ab477b7e1be"},
+]
+
+[package.dependencies]
+aiosqlite = ">=0.17.0,<1.0.0"
+alembic = ">=1.7.5,<2.0.0"
+anyio = ">=4.4.0,<5.0.0"
+apprise = ">=1.1.0,<2.0.0"
+asgi-lifespan = ">=1.0,<3.0"
+asyncpg = ">=0.23,<1.0.0"
+cachetools = ">=5.3,<6.0"
+click = ">=8.0,<8.2"
+cloudpickle = ">=2.0,<4.0"
+coolname = ">=1.0.4,<3.0.0"
+croniter = ">=1.0.12,<4.0.0"
+cryptography = ">=36.0.1"
+dateparser = ">=1.1.1,<2.0.0"
+docker = ">=4.0,<8.0"
+exceptiongroup = ">=1.0.0"
+fastapi = ">=0.111.0,<1.0.0"
+fsspec = ">=2022.5.0"
+graphviz = ">=0.20.1"
+griffe = ">=0.49.0,<2.0.0"
+httpcore = ">=1.0.5,<2.0.0"
+httpx = {version = ">=0.23,<0.23.2 || >0.23.2", extras = ["http2"]}
+humanize = ">=4.9.0,<5.0.0"
+jinja2 = ">=3.0.0,<4.0.0"
+jinja2-humanize-extension = ">=0.4.0"
+jsonpatch = ">=1.32,<2.0"
+jsonschema = ">=4.0.0,<5.0.0"
+orjson = ">=3.7,<4.0"
+packaging = ">=21.3,<24.3"
+pathspec = ">=0.8.0"
+pendulum = ">=3.0.0,<4"
+prometheus-client = ">=0.20.0"
+pydantic = ">=2.7,<3.0.0"
+pydantic-core = ">=2.12.0,<3.0.0"
+pydantic-extra-types = ">=2.8.2,<3.0.0"
+pydantic-settings = "*"
+python-dateutil = ">=2.8.2,<3.0.0"
+python-slugify = ">=5.0,<9.0"
+pytz = ">=2021.1,<2025"
+pyyaml = ">=5.4.1,<7.0.0"
+readchar = ">=4.0.0,<5.0.0"
+rfc3339-validator = ">=0.1.4,<0.2.0"
+rich = ">=11.0,<14.0"
+"ruamel.yaml" = ">=0.17.0"
+sniffio = ">=1.3.0,<2.0.0"
+sqlalchemy = {version = ">=2.0,<3.0.0", extras = ["asyncio"]}
+toml = ">=0.10.0"
+typer = ">=0.12.0,<0.12.2 || >0.12.2,<0.13.0"
+typing-extensions = ">=4.5.0,<5.0.0"
+ujson = ">=5.8.0,<6.0.0"
+uvicorn = ">=0.14.0,<0.29.0 || >0.29.0"
+websockets = ">=10.4,<14.0"
+
+[package.extras]
+aws = ["prefect-aws (>=0.5.0rc1)"]
+azure = ["prefect-azure (>=0.4.0rc1)"]
+bitbucket = ["prefect-bitbucket (>=0.3.0rc1)"]
+dask = ["prefect-dask (>=0.3.0rc1)"]
+databricks = ["prefect-databricks (>=0.3.0rc1)"]
+dbt = ["prefect-dbt (>=0.6.0rc1)"]
+dev = ["cairosvg", "codespell (>=2.2.6)", "ipython", "jinja2", "mkdocs", "mkdocs-gen-files", "mkdocs-material", "mkdocstrings[python]", "moto (>=5)", "mypy (>=1.9.0)", "numpy", "pillow", "pluggy (>=1.4.0)", "pre-commit", "pytest (>7,<9)", "pytest-asyncio (>=0.18.2,!=0.22.0,<0.23.0)", "pytest-benchmark", "pytest-codspeed", "pytest-cov", "pytest-env", "pytest-flakefinder", "pytest-timeout", "pytest-xdist (>=3.6.1)", "pyyaml", "redis (>=5.0.1)", "respx", "ruff", "setuptools", "types-PyYAML", "types-cachetools", "uv (>=0.4.5)", "vale", "vermin", "virtualenv", "watchfiles"]
+docker = ["prefect-docker (>=0.6.0rc1)"]
+email = ["prefect-email (>=0.4.0rc1)"]
+gcp = ["prefect-gcp (>=0.6.0rc1)"]
+github = ["prefect-github (>=0.3.0rc1)"]
+gitlab = ["prefect-gitlab (>=0.3.0rc1)"]
+kubernetes = ["prefect-kubernetes (>=0.4.0rc1)"]
+ray = ["prefect-ray (>=0.4.0rc1)"]
+redis = ["prefect-redis (>=0.2.0)"]
+shell = ["prefect-shell (>=0.3.0rc1)"]
+slack = ["prefect-slack (>=0.3.0rc1)"]
+snowflake = ["prefect-snowflake (>=0.28.0rc1)"]
+sqlalchemy = ["prefect-sqlalchemy (>=0.5.0rc1)"]
+
[[package]]
name = "prometheus-client"
-version = "0.20.0"
+version = "0.21.0"
description = "Python client for the Prometheus monitoring system."
optional = false
python-versions = ">=3.8"
files = [
- {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"},
- {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"},
+ {file = "prometheus_client-0.21.0-py3-none-any.whl", hash = "sha256:4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166"},
+ {file = "prometheus_client-0.21.0.tar.gz", hash = "sha256:96c83c606b71ff2b0a433c98889d275f51ffec6c5e267de37c7a2b5c9aa9233e"},
]
[package.extras]
@@ -3355,22 +4075,22 @@ wcwidth = "*"
[[package]]
name = "protobuf"
-version = "4.25.4"
+version = "4.25.5"
description = ""
optional = false
python-versions = ">=3.8"
files = [
- {file = "protobuf-4.25.4-cp310-abi3-win32.whl", hash = "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4"},
- {file = "protobuf-4.25.4-cp310-abi3-win_amd64.whl", hash = "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d"},
- {file = "protobuf-4.25.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b"},
- {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835"},
- {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040"},
- {file = "protobuf-4.25.4-cp38-cp38-win32.whl", hash = "sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1"},
- {file = "protobuf-4.25.4-cp38-cp38-win_amd64.whl", hash = "sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1"},
- {file = "protobuf-4.25.4-cp39-cp39-win32.whl", hash = "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca"},
- {file = "protobuf-4.25.4-cp39-cp39-win_amd64.whl", hash = "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f"},
- {file = "protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978"},
- {file = "protobuf-4.25.4.tar.gz", hash = "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d"},
+ {file = "protobuf-4.25.5-cp310-abi3-win32.whl", hash = "sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8"},
+ {file = "protobuf-4.25.5-cp310-abi3-win_amd64.whl", hash = "sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea"},
+ {file = "protobuf-4.25.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2fde3d805354df675ea4c7c6338c1aecd254dfc9925e88c6d31a2bcb97eb173"},
+ {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:919ad92d9b0310070f8356c24b855c98df2b8bd207ebc1c0c6fcc9ab1e007f3d"},
+ {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fe14e16c22be926d3abfcb500e60cab068baf10b542b8c858fa27e098123e331"},
+ {file = "protobuf-4.25.5-cp38-cp38-win32.whl", hash = "sha256:98d8d8aa50de6a2747efd9cceba361c9034050ecce3e09136f90de37ddba66e1"},
+ {file = "protobuf-4.25.5-cp38-cp38-win_amd64.whl", hash = "sha256:b0234dd5a03049e4ddd94b93400b67803c823cfc405689688f59b34e0742381a"},
+ {file = "protobuf-4.25.5-cp39-cp39-win32.whl", hash = "sha256:abe32aad8561aa7cc94fc7ba4fdef646e576983edb94a73381b03c53728a626f"},
+ {file = "protobuf-4.25.5-cp39-cp39-win_amd64.whl", hash = "sha256:7a183f592dc80aa7c8da7ad9e55091c4ffc9497b3054452d629bb85fa27c2a45"},
+ {file = "protobuf-4.25.5-py3-none-any.whl", hash = "sha256:0aebecb809cae990f8129ada5ca273d9d670b76d9bfc9b1809f0a9c02b7dbf41"},
+ {file = "protobuf-4.25.5.tar.gz", hash = "sha256:7f8249476b4a9473645db7f8ab42b02fe1488cbe5fb72fddd445e0665afd8584"},
]
[[package]]
@@ -3607,6 +4327,28 @@ files = [
[package.dependencies]
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
+[[package]]
+name = "pydantic-extra-types"
+version = "2.9.0"
+description = "Extra Pydantic types."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pydantic_extra_types-2.9.0-py3-none-any.whl", hash = "sha256:f0bb975508572ba7bf3390b7337807588463b7248587e69f43b1ad7c797530d0"},
+ {file = "pydantic_extra_types-2.9.0.tar.gz", hash = "sha256:e061c01636188743bb69f368dcd391f327b8cfbfede2fe1cbb1211b06601ba3b"},
+]
+
+[package.dependencies]
+pydantic = ">=2.5.2"
+
+[package.extras]
+all = ["pendulum (>=3.0.0,<4.0.0)", "phonenumbers (>=8,<9)", "pycountry (>=23)", "python-ulid (>=1,<2)", "python-ulid (>=1,<3)", "pytz (>=2024.1)", "semver (>=3.0.2)", "tzdata (>=2024.1)"]
+pendulum = ["pendulum (>=3.0.0,<4.0.0)"]
+phonenumbers = ["phonenumbers (>=8,<9)"]
+pycountry = ["pycountry (>=23)"]
+python-ulid = ["python-ulid (>=1,<2)", "python-ulid (>=1,<3)"]
+semver = ["semver (>=3.0.2)"]
+
[[package]]
name = "pydantic-settings"
version = "2.2.1"
@@ -3815,6 +4557,24 @@ pytest = ">=4.6"
[package.extras]
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
+[[package]]
+name = "pytest-env"
+version = "1.1.3"
+description = "pytest plugin that allows you to add environment variables."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest_env-1.1.3-py3-none-any.whl", hash = "sha256:aada77e6d09fcfb04540a6e462c58533c37df35fa853da78707b17ec04d17dfc"},
+ {file = "pytest_env-1.1.3.tar.gz", hash = "sha256:fcd7dc23bb71efd3d35632bde1bbe5ee8c8dc4489d6617fb010674880d96216b"},
+]
+
+[package.dependencies]
+pytest = ">=7.4.3"
+tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
+
+[package.extras]
+test = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "pytest-mock (>=3.12)"]
+
[[package]]
name = "pytest-httpx"
version = "0.30.0"
@@ -3833,6 +4593,20 @@ pytest = ">=7,<9"
[package.extras]
testing = ["pytest-asyncio (==0.23.*)", "pytest-cov (==4.*)"]
+[[package]]
+name = "pytest-timeout"
+version = "2.3.1"
+description = "pytest plugin to abort hanging tests"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9"},
+ {file = "pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e"},
+]
+
+[package.dependencies]
+pytest = ">=7.0.0"
+
[[package]]
name = "pytest-xdist"
version = "3.4.0"
@@ -3895,15 +4669,32 @@ files = [
[package.extras]
dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"]
+[[package]]
+name = "python-slugify"
+version = "8.0.4"
+description = "A Python slugify application that also handles Unicode"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"},
+ {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"},
+]
+
+[package.dependencies]
+text-unidecode = ">=1.3"
+
+[package.extras]
+unidecode = ["Unidecode (>=1.1.1)"]
+
[[package]]
name = "pytz"
-version = "2024.1"
+version = "2024.2"
description = "World timezone definitions, modern and historical"
optional = false
python-versions = "*"
files = [
- {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"},
- {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"},
+ {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
+ {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
]
[[package]]
@@ -4112,6 +4903,17 @@ files = [
[package.dependencies]
cffi = {version = "*", markers = "implementation_name == \"pypy\""}
+[[package]]
+name = "readchar"
+version = "4.2.0"
+description = "Library to easily read single chars and key strokes"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "readchar-4.2.0-py3-none-any.whl", hash = "sha256:2a587a27c981e6d25a518730ad4c88c429c315439baa6fda55d7a8b3ac4cb62a"},
+ {file = "readchar-4.2.0.tar.gz", hash = "sha256:44807cbbe377b72079fea6cba8aa91c809982d7d727b2f0dbb2d1a8084914faa"},
+]
+
[[package]]
name = "redis"
version = "5.0.8"
@@ -4131,6 +4933,124 @@ hiredis = {version = ">1.0.0", optional = true, markers = "extra == \"hiredis\""
hiredis = ["hiredis (>1.0.0)"]
ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
+[[package]]
+name = "referencing"
+version = "0.35.1"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"},
+ {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+
+[[package]]
+name = "regex"
+version = "2024.9.11"
+description = "Alternative regular expression module, to replace re."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"},
+ {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"},
+ {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"},
+ {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"},
+ {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"},
+ {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"},
+ {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"},
+ {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"},
+ {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"},
+ {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"},
+ {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"},
+ {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"},
+ {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"},
+ {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"},
+ {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"},
+ {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"},
+ {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"},
+ {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"},
+ {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"},
+ {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"},
+ {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"},
+ {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"},
+ {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"},
+ {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"},
+ {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"},
+ {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"},
+ {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"},
+ {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"},
+ {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"},
+ {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"},
+ {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"},
+ {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"},
+ {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"},
+ {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"},
+ {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"},
+ {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"},
+ {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"},
+ {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"},
+ {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"},
+ {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"},
+ {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"},
+ {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"},
+ {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"},
+ {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"},
+ {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"},
+ {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"},
+ {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"},
+ {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"},
+ {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"},
+ {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"},
+ {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"},
+ {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"},
+ {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"},
+ {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"},
+ {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"},
+ {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"},
+ {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"},
+ {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"},
+ {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"},
+ {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"},
+ {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"},
+ {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"},
+ {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"},
+ {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"},
+ {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"},
+ {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"},
+ {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"},
+ {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"},
+ {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"},
+ {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"},
+ {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"},
+ {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"},
+ {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"},
+ {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"},
+ {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"},
+ {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"},
+ {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"},
+ {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"},
+ {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"},
+ {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"},
+ {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"},
+ {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"},
+ {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"},
+ {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"},
+ {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"},
+ {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"},
+ {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"},
+ {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"},
+ {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"},
+ {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"},
+ {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"},
+ {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"},
+ {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"},
+ {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"},
+]
+
[[package]]
name = "requests"
version = "2.32.3"
@@ -4152,15 +5072,47 @@ urllib3 = ">=1.21.1,<3"
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+[[package]]
+name = "requests-oauthlib"
+version = "2.0.0"
+description = "OAuthlib authentication support for Requests."
+optional = false
+python-versions = ">=3.4"
+files = [
+ {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"},
+ {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"},
+]
+
+[package.dependencies]
+oauthlib = ">=3.0.0"
+requests = ">=2.0.0"
+
+[package.extras]
+rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
+
+[[package]]
+name = "rfc3339-validator"
+version = "0.1.4"
+description = "A pure python RFC3339 validator"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"},
+ {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"},
+]
+
+[package.dependencies]
+six = "*"
+
[[package]]
name = "rich"
-version = "13.8.0"
+version = "13.8.1"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false
python-versions = ">=3.7.0"
files = [
- {file = "rich-13.8.0-py3-none-any.whl", hash = "sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc"},
- {file = "rich-13.8.0.tar.gz", hash = "sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4"},
+ {file = "rich-13.8.1-py3-none-any.whl", hash = "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06"},
+ {file = "rich-13.8.1.tar.gz", hash = "sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a"},
]
[package.dependencies]
@@ -4170,31 +5122,220 @@ pygments = ">=2.13.0,<3.0.0"
[package.extras]
jupyter = ["ipywidgets (>=7.5.1,<9)"]
+[[package]]
+name = "rpds-py"
+version = "0.20.0"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "rpds_py-0.20.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3ad0fda1635f8439cde85c700f964b23ed5fc2d28016b32b9ee5fe30da5c84e2"},
+ {file = "rpds_py-0.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9bb4a0d90fdb03437c109a17eade42dfbf6190408f29b2744114d11586611d6f"},
+ {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6377e647bbfd0a0b159fe557f2c6c602c159fc752fa316572f012fc0bf67150"},
+ {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb851b7df9dda52dc1415ebee12362047ce771fc36914586b2e9fcbd7d293b3e"},
+ {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e0f80b739e5a8f54837be5d5c924483996b603d5502bfff79bf33da06164ee2"},
+ {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a8c94dad2e45324fc74dce25e1645d4d14df9a4e54a30fa0ae8bad9a63928e3"},
+ {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e604fe73ba048c06085beaf51147eaec7df856824bfe7b98657cf436623daf"},
+ {file = "rpds_py-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:df3de6b7726b52966edf29663e57306b23ef775faf0ac01a3e9f4012a24a4140"},
+ {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf258ede5bc22a45c8e726b29835b9303c285ab46fc7c3a4cc770736b5304c9f"},
+ {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:55fea87029cded5df854ca7e192ec7bdb7ecd1d9a3f63d5c4eb09148acf4a7ce"},
+ {file = "rpds_py-0.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ae94bd0b2f02c28e199e9bc51485d0c5601f58780636185660f86bf80c89af94"},
+ {file = "rpds_py-0.20.0-cp310-none-win32.whl", hash = "sha256:28527c685f237c05445efec62426d285e47a58fb05ba0090a4340b73ecda6dee"},
+ {file = "rpds_py-0.20.0-cp310-none-win_amd64.whl", hash = "sha256:238a2d5b1cad28cdc6ed15faf93a998336eb041c4e440dd7f902528b8891b399"},
+ {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"},
+ {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"},
+ {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"},
+ {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"},
+ {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"},
+ {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"},
+ {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"},
+ {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"},
+ {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"},
+ {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"},
+ {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"},
+ {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"},
+ {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"},
+ {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"},
+ {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"},
+ {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"},
+ {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b80d4a7900cf6b66bb9cee5c352b2d708e29e5a37fe9bf784fa97fc11504bf6c"},
+ {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50eccbf054e62a7b2209b28dc7a22d6254860209d6753e6b78cfaeb0075d7bee"},
+ {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:49a8063ea4296b3a7e81a5dfb8f7b2d73f0b1c20c2af401fb0cdf22e14711a96"},
+ {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea438162a9fcbee3ecf36c23e6c68237479f89f962f82dae83dc15feeceb37e4"},
+ {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18d7585c463087bddcfa74c2ba267339f14f2515158ac4db30b1f9cbdb62c8ef"},
+ {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d4c7d1a051eeb39f5c9547e82ea27cbcc28338482242e3e0b7768033cb083821"},
+ {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4df1e3b3bec320790f699890d41c59d250f6beda159ea3c44c3f5bac1976940"},
+ {file = "rpds_py-0.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cf126d33a91ee6eedc7f3197b53e87a2acdac63602c0f03a02dd69e4b138174"},
+ {file = "rpds_py-0.20.0-cp312-none-win32.whl", hash = "sha256:8bc7690f7caee50b04a79bf017a8d020c1f48c2a1077ffe172abec59870f1139"},
+ {file = "rpds_py-0.20.0-cp312-none-win_amd64.whl", hash = "sha256:0e13e6952ef264c40587d510ad676a988df19adea20444c2b295e536457bc585"},
+ {file = "rpds_py-0.20.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:aa9a0521aeca7d4941499a73ad7d4f8ffa3d1affc50b9ea11d992cd7eff18a29"},
+ {file = "rpds_py-0.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1f1d51eccb7e6c32ae89243cb352389228ea62f89cd80823ea7dd1b98e0b91"},
+ {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a86a9b96070674fc88b6f9f71a97d2c1d3e5165574615d1f9168ecba4cecb24"},
+ {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c8ef2ebf76df43f5750b46851ed1cdf8f109d7787ca40035fe19fbdc1acc5a7"},
+ {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b74b25f024b421d5859d156750ea9a65651793d51b76a2e9238c05c9d5f203a9"},
+ {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57eb94a8c16ab08fef6404301c38318e2c5a32216bf5de453e2714c964c125c8"},
+ {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1940dae14e715e2e02dfd5b0f64a52e8374a517a1e531ad9412319dc3ac7879"},
+ {file = "rpds_py-0.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d20277fd62e1b992a50c43f13fbe13277a31f8c9f70d59759c88f644d66c619f"},
+ {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:06db23d43f26478303e954c34c75182356ca9aa7797d22c5345b16871ab9c45c"},
+ {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2a5db5397d82fa847e4c624b0c98fe59d2d9b7cf0ce6de09e4d2e80f8f5b3f2"},
+ {file = "rpds_py-0.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a35df9f5548fd79cb2f52d27182108c3e6641a4feb0f39067911bf2adaa3e57"},
+ {file = "rpds_py-0.20.0-cp313-none-win32.whl", hash = "sha256:fd2d84f40633bc475ef2d5490b9c19543fbf18596dcb1b291e3a12ea5d722f7a"},
+ {file = "rpds_py-0.20.0-cp313-none-win_amd64.whl", hash = "sha256:9bc2d153989e3216b0559251b0c260cfd168ec78b1fac33dd485750a228db5a2"},
+ {file = "rpds_py-0.20.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f2fbf7db2012d4876fb0d66b5b9ba6591197b0f165db8d99371d976546472a24"},
+ {file = "rpds_py-0.20.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1e5f3cd7397c8f86c8cc72d5a791071431c108edd79872cdd96e00abd8497d29"},
+ {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce9845054c13696f7af7f2b353e6b4f676dab1b4b215d7fe5e05c6f8bb06f965"},
+ {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c3e130fd0ec56cb76eb49ef52faead8ff09d13f4527e9b0c400307ff72b408e1"},
+ {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b16aa0107ecb512b568244ef461f27697164d9a68d8b35090e9b0c1c8b27752"},
+ {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa7f429242aae2947246587d2964fad750b79e8c233a2367f71b554e9447949c"},
+ {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0fc424a5842a11e28956e69395fbbeab2c97c42253169d87e90aac2886d751"},
+ {file = "rpds_py-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8c00a3b1e70c1d3891f0db1b05292747f0dbcfb49c43f9244d04c70fbc40eb8"},
+ {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:40ce74fc86ee4645d0a225498d091d8bc61f39b709ebef8204cb8b5a464d3c0e"},
+ {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4fe84294c7019456e56d93e8ababdad5a329cd25975be749c3f5f558abb48253"},
+ {file = "rpds_py-0.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:338ca4539aad4ce70a656e5187a3a31c5204f261aef9f6ab50e50bcdffaf050a"},
+ {file = "rpds_py-0.20.0-cp38-none-win32.whl", hash = "sha256:54b43a2b07db18314669092bb2de584524d1ef414588780261e31e85846c26a5"},
+ {file = "rpds_py-0.20.0-cp38-none-win_amd64.whl", hash = "sha256:a1862d2d7ce1674cffa6d186d53ca95c6e17ed2b06b3f4c476173565c862d232"},
+ {file = "rpds_py-0.20.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3fde368e9140312b6e8b6c09fb9f8c8c2f00999d1823403ae90cc00480221b22"},
+ {file = "rpds_py-0.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9824fb430c9cf9af743cf7aaf6707bf14323fb51ee74425c380f4c846ea70789"},
+ {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11ef6ce74616342888b69878d45e9f779b95d4bd48b382a229fe624a409b72c5"},
+ {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c52d3f2f82b763a24ef52f5d24358553e8403ce05f893b5347098014f2d9eff2"},
+ {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d35cef91e59ebbeaa45214861874bc6f19eb35de96db73e467a8358d701a96c"},
+ {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72278a30111e5b5525c1dd96120d9e958464316f55adb030433ea905866f4de"},
+ {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4c29cbbba378759ac5786730d1c3cb4ec6f8ababf5c42a9ce303dc4b3d08cda"},
+ {file = "rpds_py-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6632f2d04f15d1bd6fe0eedd3b86d9061b836ddca4c03d5cf5c7e9e6b7c14580"},
+ {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d0b67d87bb45ed1cd020e8fbf2307d449b68abc45402fe1a4ac9e46c3c8b192b"},
+ {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ec31a99ca63bf3cd7f1a5ac9fe95c5e2d060d3c768a09bc1d16e235840861420"},
+ {file = "rpds_py-0.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e6c9976e38f4d8c4a63bd8a8edac5307dffd3ee7e6026d97f3cc3a2dc02a0b"},
+ {file = "rpds_py-0.20.0-cp39-none-win32.whl", hash = "sha256:569b3ea770c2717b730b61998b6c54996adee3cef69fc28d444f3e7920313cf7"},
+ {file = "rpds_py-0.20.0-cp39-none-win_amd64.whl", hash = "sha256:e6900ecdd50ce0facf703f7a00df12374b74bbc8ad9fe0f6559947fb20f82364"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:617c7357272c67696fd052811e352ac54ed1d9b49ab370261a80d3b6ce385045"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9426133526f69fcaba6e42146b4e12d6bc6c839b8b555097020e2b78ce908dcc"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deb62214c42a261cb3eb04d474f7155279c1a8a8c30ac89b7dcb1721d92c3c02"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcaeb7b57f1a1e071ebd748984359fef83ecb026325b9d4ca847c95bc7311c92"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d454b8749b4bd70dd0a79f428731ee263fa6995f83ccb8bada706e8d1d3ff89d"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d807dc2051abe041b6649681dce568f8e10668e3c1c6543ebae58f2d7e617855"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c20f0ddeb6e29126d45f89206b8291352b8c5b44384e78a6499d68b52ae511"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7f19250ceef892adf27f0399b9e5afad019288e9be756d6919cb58892129f51"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4f1ed4749a08379555cebf4650453f14452eaa9c43d0a95c49db50c18b7da075"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dcedf0b42bcb4cfff4101d7771a10532415a6106062f005ab97d1d0ab5681c60"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:39ed0d010457a78f54090fafb5d108501b5aa5604cc22408fc1c0c77eac14344"},
+ {file = "rpds_py-0.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bb273176be34a746bdac0b0d7e4e2c467323d13640b736c4c477881a3220a989"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f918a1a130a6dfe1d7fe0f105064141342e7dd1611f2e6a21cd2f5c8cb1cfb3e"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:f60012a73aa396be721558caa3a6fd49b3dd0033d1675c6d59c4502e870fcf0c"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d2b1ad682a3dfda2a4e8ad8572f3100f95fad98cb99faf37ff0ddfe9cbf9d03"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:614fdafe9f5f19c63ea02817fa4861c606a59a604a77c8cdef5aa01d28b97921"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa518bcd7600c584bf42e6617ee8132869e877db2f76bcdc281ec6a4113a53ab"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0475242f447cc6cb8a9dd486d68b2ef7fbee84427124c232bff5f63b1fe11e5"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90a4cd061914a60bd51c68bcb4357086991bd0bb93d8aa66a6da7701370708f"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:def7400461c3a3f26e49078302e1c1b38f6752342c77e3cf72ce91ca69fb1bc1"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:65794e4048ee837494aea3c21a28ad5fc080994dfba5b036cf84de37f7ad5074"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:faefcc78f53a88f3076b7f8be0a8f8d35133a3ecf7f3770895c25f8813460f08"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5b4f105deeffa28bbcdff6c49b34e74903139afa690e35d2d9e3c2c2fba18cec"},
+ {file = "rpds_py-0.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fdfc3a892927458d98f3d55428ae46b921d1f7543b89382fdb483f5640daaec8"},
+ {file = "rpds_py-0.20.0.tar.gz", hash = "sha256:d72a210824facfdaf8768cf2d7ca25a042c30320b3020de2fa04640920d4e121"},
+]
+
+[[package]]
+name = "ruamel-yaml"
+version = "0.18.6"
+description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"},
+ {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"},
+]
+
+[package.dependencies]
+"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""}
+
+[package.extras]
+docs = ["mercurial (>5.7)", "ryd"]
+jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
+
+[[package]]
+name = "ruamel-yaml-clib"
+version = "0.2.8"
+description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"},
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"},
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"},
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"},
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"},
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"},
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"},
+ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"},
+ {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"},
+ {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"},
+ {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"},
+ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"},
+ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"},
+ {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"},
+ {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"},
+]
+
[[package]]
name = "ruff"
-version = "0.5.0"
+version = "0.6.6"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.5.0-py3-none-linux_armv6l.whl", hash = "sha256:ee770ea8ab38918f34e7560a597cc0a8c9a193aaa01bfbd879ef43cb06bd9c4c"},
- {file = "ruff-0.5.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38f3b8327b3cb43474559d435f5fa65dacf723351c159ed0dc567f7ab735d1b6"},
- {file = "ruff-0.5.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7594f8df5404a5c5c8f64b8311169879f6cf42142da644c7e0ba3c3f14130370"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adc7012d6ec85032bc4e9065110df205752d64010bed5f958d25dbee9ce35de3"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d505fb93b0fabef974b168d9b27c3960714d2ecda24b6ffa6a87ac432905ea38"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dc5cfd3558f14513ed0d5b70ce531e28ea81a8a3b1b07f0f48421a3d9e7d80a"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:db3ca35265de239a1176d56a464b51557fce41095c37d6c406e658cf80bbb362"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b1a321c4f68809fddd9b282fab6a8d8db796b270fff44722589a8b946925a2a8"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c4dfcd8d34b143916994b3876b63d53f56724c03f8c1a33a253b7b1e6bf2a7d"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81e5facfc9f4a674c6a78c64d38becfbd5e4f739c31fcd9ce44c849f1fad9e4c"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e589e27971c2a3efff3fadafb16e5aef7ff93250f0134ec4b52052b673cf988d"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2ffbc3715a52b037bcb0f6ff524a9367f642cdc5817944f6af5479bbb2eb50e"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cd096e23c6a4f9c819525a437fa0a99d1c67a1b6bb30948d46f33afbc53596cf"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:46e193b36f2255729ad34a49c9a997d506e58f08555366b2108783b3064a0e1e"},
- {file = "ruff-0.5.0-py3-none-win32.whl", hash = "sha256:49141d267100f5ceff541b4e06552e98527870eafa1acc9dec9139c9ec5af64c"},
- {file = "ruff-0.5.0-py3-none-win_amd64.whl", hash = "sha256:e9118f60091047444c1b90952736ee7b1792910cab56e9b9a9ac20af94cd0440"},
- {file = "ruff-0.5.0-py3-none-win_arm64.whl", hash = "sha256:ed5c4df5c1fb4518abcb57725b576659542bdbe93366f4f329e8f398c4b71178"},
- {file = "ruff-0.5.0.tar.gz", hash = "sha256:eb641b5873492cf9bd45bc9c5ae5320648218e04386a5f0c264ad6ccce8226a1"},
+ {file = "ruff-0.6.6-py3-none-linux_armv6l.whl", hash = "sha256:f5bc5398457484fc0374425b43b030e4668ed4d2da8ee7fdda0e926c9f11ccfb"},
+ {file = "ruff-0.6.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:515a698254c9c47bb84335281a170213b3ee5eb47feebe903e1be10087a167ce"},
+ {file = "ruff-0.6.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6bb1b4995775f1837ab70f26698dd73852bbb82e8f70b175d2713c0354fe9182"},
+ {file = "ruff-0.6.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69c546f412dfae8bb9cc4f27f0e45cdd554e42fecbb34f03312b93368e1cd0a6"},
+ {file = "ruff-0.6.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:59627e97364329e4eae7d86fa7980c10e2b129e2293d25c478ebcb861b3e3fd6"},
+ {file = "ruff-0.6.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94c3f78c3d32190aafbb6bc5410c96cfed0a88aadb49c3f852bbc2aa9783a7d8"},
+ {file = "ruff-0.6.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:704da526c1e137f38c8a067a4a975fe6834b9f8ba7dbc5fd7503d58148851b8f"},
+ {file = "ruff-0.6.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:efeede5815a24104579a0f6320660536c5ffc1c91ae94f8c65659af915fb9de9"},
+ {file = "ruff-0.6.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e368aef0cc02ca3593eae2fb8186b81c9c2b3f39acaaa1108eb6b4d04617e61f"},
+ {file = "ruff-0.6.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2653fc3b2a9315bd809725c88dd2446550099728d077a04191febb5ea79a4f79"},
+ {file = "ruff-0.6.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:bb858cd9ce2d062503337c5b9784d7b583bcf9d1a43c4df6ccb5eab774fbafcb"},
+ {file = "ruff-0.6.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:488f8e15c01ea9afb8c0ba35d55bd951f484d0c1b7c5fd746ce3c47ccdedce68"},
+ {file = "ruff-0.6.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:aefb0bd15f1cfa4c9c227b6120573bb3d6c4ee3b29fb54a5ad58f03859bc43c6"},
+ {file = "ruff-0.6.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a4c0698cc780bcb2c61496cbd56b6a3ac0ad858c966652f7dbf4ceb029252fbe"},
+ {file = "ruff-0.6.6-py3-none-win32.whl", hash = "sha256:aadf81ddc8ab5b62da7aae78a91ec933cbae9f8f1663ec0325dae2c364e4ad84"},
+ {file = "ruff-0.6.6-py3-none-win_amd64.whl", hash = "sha256:0adb801771bc1f1b8cf4e0a6fdc30776e7c1894810ff3b344e50da82ef50eeb1"},
+ {file = "ruff-0.6.6-py3-none-win_arm64.whl", hash = "sha256:4b4d32c137bc781c298964dd4e52f07d6f7d57c03eae97a72d97856844aa510a"},
+ {file = "ruff-0.6.6.tar.gz", hash = "sha256:0fc030b6fd14814d69ac0196396f6761921bd20831725c7361e1b8100b818034"},
]
[[package]]
@@ -4216,18 +5357,18 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"]
[[package]]
name = "setuptools"
-version = "74.1.2"
+version = "75.1.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
- {file = "setuptools-74.1.2-py3-none-any.whl", hash = "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308"},
- {file = "setuptools-74.1.2.tar.gz", hash = "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6"},
+ {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"},
+ {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"},
]
[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"]
-core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
+core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
enabler = ["pytest-enabler (>=2.2)"]
@@ -4278,6 +5419,93 @@ files = [
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
+[[package]]
+name = "sqlalchemy"
+version = "2.0.35"
+description = "Database Abstraction Library"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67219632be22f14750f0d1c70e62f204ba69d28f62fd6432ba05ab295853de9b"},
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4668bd8faf7e5b71c0319407b608f278f279668f358857dbfd10ef1954ac9f90"},
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8bea573863762bbf45d1e13f87c2d2fd32cee2dbd50d050f83f87429c9e1ea"},
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f552023710d4b93d8fb29a91fadf97de89c5926c6bd758897875435f2a939f33"},
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:016b2e665f778f13d3c438651dd4de244214b527a275e0acf1d44c05bc6026a9"},
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7befc148de64b6060937231cbff8d01ccf0bfd75aa26383ffdf8d82b12ec04ff"},
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-win32.whl", hash = "sha256:22b83aed390e3099584b839b93f80a0f4a95ee7f48270c97c90acd40ee646f0b"},
+ {file = "SQLAlchemy-2.0.35-cp310-cp310-win_amd64.whl", hash = "sha256:a29762cd3d116585278ffb2e5b8cc311fb095ea278b96feef28d0b423154858e"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e21f66748ab725ade40fa7af8ec8b5019c68ab00b929f6643e1b1af461eddb60"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a6219108a15fc6d24de499d0d515c7235c617b2540d97116b663dade1a54d62"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:042622a5306c23b972192283f4e22372da3b8ddf5f7aac1cc5d9c9b222ab3ff6"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:627dee0c280eea91aed87b20a1f849e9ae2fe719d52cbf847c0e0ea34464b3f7"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4fdcd72a789c1c31ed242fd8c1bcd9ea186a98ee8e5408a50e610edfef980d71"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89b64cd8898a3a6f642db4eb7b26d1b28a497d4022eccd7717ca066823e9fb01"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-win32.whl", hash = "sha256:6a93c5a0dfe8d34951e8a6f499a9479ffb9258123551fa007fc708ae2ac2bc5e"},
+ {file = "SQLAlchemy-2.0.35-cp311-cp311-win_amd64.whl", hash = "sha256:c68fe3fcde03920c46697585620135b4ecfdfc1ed23e75cc2c2ae9f8502c10b8"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eb60b026d8ad0c97917cb81d3662d0b39b8ff1335e3fabb24984c6acd0c900a2"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6921ee01caf375363be5e9ae70d08ce7ca9d7e0e8983183080211a062d299468"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cdf1a0dbe5ced887a9b127da4ffd7354e9c1a3b9bb330dce84df6b70ccb3a8d"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93a71c8601e823236ac0e5d087e4f397874a421017b3318fd92c0b14acf2b6db"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e04b622bb8a88f10e439084486f2f6349bf4d50605ac3e445869c7ea5cf0fa8c"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1b56961e2d31389aaadf4906d453859f35302b4eb818d34a26fab72596076bb8"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-win32.whl", hash = "sha256:0f9f3f9a3763b9c4deb8c5d09c4cc52ffe49f9876af41cc1b2ad0138878453cf"},
+ {file = "SQLAlchemy-2.0.35-cp312-cp312-win_amd64.whl", hash = "sha256:25b0f63e7fcc2a6290cb5f7f5b4fc4047843504983a28856ce9b35d8f7de03cc"},
+ {file = "SQLAlchemy-2.0.35-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f021d334f2ca692523aaf7bbf7592ceff70c8594fad853416a81d66b35e3abf9"},
+ {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05c3f58cf91683102f2f0265c0db3bd3892e9eedabe059720492dbaa4f922da1"},
+ {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:032d979ce77a6c2432653322ba4cbeabf5a6837f704d16fa38b5a05d8e21fa00"},
+ {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:2e795c2f7d7249b75bb5f479b432a51b59041580d20599d4e112b5f2046437a3"},
+ {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:cc32b2990fc34380ec2f6195f33a76b6cdaa9eecf09f0c9404b74fc120aef36f"},
+ {file = "SQLAlchemy-2.0.35-cp37-cp37m-win32.whl", hash = "sha256:9509c4123491d0e63fb5e16199e09f8e262066e58903e84615c301dde8fa2e87"},
+ {file = "SQLAlchemy-2.0.35-cp37-cp37m-win_amd64.whl", hash = "sha256:3655af10ebcc0f1e4e06c5900bb33e080d6a1fa4228f502121f28a3b1753cde5"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4c31943b61ed8fdd63dfd12ccc919f2bf95eefca133767db6fbbd15da62078ec"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a62dd5d7cc8626a3634208df458c5fe4f21200d96a74d122c83bc2015b333bc1"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0630774b0977804fba4b6bbea6852ab56c14965a2b0c7fc7282c5f7d90a1ae72"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d625eddf7efeba2abfd9c014a22c0f6b3796e0ffb48f5d5ab106568ef01ff5a"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ada603db10bb865bbe591939de854faf2c60f43c9b763e90f653224138f910d9"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c41411e192f8d3ea39ea70e0fae48762cd11a2244e03751a98bd3c0ca9a4e936"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-win32.whl", hash = "sha256:d299797d75cd747e7797b1b41817111406b8b10a4f88b6e8fe5b5e59598b43b0"},
+ {file = "SQLAlchemy-2.0.35-cp38-cp38-win_amd64.whl", hash = "sha256:0375a141e1c0878103eb3d719eb6d5aa444b490c96f3fedab8471c7f6ffe70ee"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccae5de2a0140d8be6838c331604f91d6fafd0735dbdcee1ac78fc8fbaba76b4"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a275a806f73e849e1c309ac11108ea1a14cd7058577aba962cd7190e27c9e3c"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:732e026240cdd1c1b2e3ac515c7a23820430ed94292ce33806a95869c46bd139"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890da8cd1941fa3dab28c5bac3b9da8502e7e366f895b3b8e500896f12f94d11"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0d8326269dbf944b9201911b0d9f3dc524d64779a07518199a58384c3d37a44"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b76d63495b0508ab9fc23f8152bac63205d2a704cd009a2b0722f4c8e0cba8e0"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-win32.whl", hash = "sha256:69683e02e8a9de37f17985905a5eca18ad651bf592314b4d3d799029797d0eb3"},
+ {file = "SQLAlchemy-2.0.35-cp39-cp39-win_amd64.whl", hash = "sha256:aee110e4ef3c528f3abbc3c2018c121e708938adeeff9006428dd7c8555e9b3f"},
+ {file = "SQLAlchemy-2.0.35-py3-none-any.whl", hash = "sha256:2ab3f0336c0387662ce6221ad30ab3a5e6499aab01b9790879b6578fd9b8faa1"},
+ {file = "sqlalchemy-2.0.35.tar.gz", hash = "sha256:e11d7ea4d24f0a262bccf9a7cd6284c976c5369dac21db237cff59586045ab9f"},
+]
+
+[package.dependencies]
+greenlet = {version = "!=0.4.17", optional = true, markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\") or extra == \"asyncio\""}
+typing-extensions = ">=4.6.0"
+
+[package.extras]
+aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
+aioodbc = ["aioodbc", "greenlet (!=0.4.17)"]
+aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
+asyncio = ["greenlet (!=0.4.17)"]
+asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"]
+mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"]
+mssql = ["pyodbc"]
+mssql-pymssql = ["pymssql"]
+mssql-pyodbc = ["pyodbc"]
+mypy = ["mypy (>=0.910)"]
+mysql = ["mysqlclient (>=1.4.0)"]
+mysql-connector = ["mysql-connector-python"]
+oracle = ["cx_oracle (>=8)"]
+oracle-oracledb = ["oracledb (>=1.0.1)"]
+postgresql = ["psycopg2 (>=2.7)"]
+postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
+postgresql-pg8000 = ["pg8000 (>=1.29.1)"]
+postgresql-psycopg = ["psycopg (>=3.0.7)"]
+postgresql-psycopg2binary = ["psycopg2-binary"]
+postgresql-psycopg2cffi = ["psycopg2cffi"]
+postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
+pymysql = ["pymysql"]
+sqlcipher = ["sqlcipher3_binary"]
+
[[package]]
name = "stack-data"
version = "0.6.3"
@@ -4299,13 +5527,13 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
[[package]]
name = "starlette"
-version = "0.38.5"
+version = "0.38.6"
description = "The little ASGI library that shines."
optional = false
python-versions = ">=3.8"
files = [
- {file = "starlette-0.38.5-py3-none-any.whl", hash = "sha256:632f420a9d13e3ee2a6f18f437b0a9f1faecb0bc42e1942aa2ea0e379a4c4206"},
- {file = "starlette-0.38.5.tar.gz", hash = "sha256:04a92830a9b6eb1442c766199d62260c3d4dc9c4f9188360626b1e0273cb7077"},
+ {file = "starlette-0.38.6-py3-none-any.whl", hash = "sha256:4517a1409e2e73ee4951214ba012052b9e16f60e90d73cfb06192c19203bbb05"},
+ {file = "starlette-0.38.6.tar.gz", hash = "sha256:863a1588f5574e70a821dadefb41e4881ea451a47a3cd1b4df359d4ffefe5ead"},
]
[package.dependencies]
@@ -4346,6 +5574,69 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-
tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"]
typing = ["mypy (>=1.4)", "rich", "twisted"]
+[[package]]
+name = "testcontainers"
+version = "4.8.1"
+description = "Python library for throwaway instances of anything that can run in a Docker container"
+optional = false
+python-versions = "<4.0,>=3.9"
+files = [
+ {file = "testcontainers-4.8.1-py3-none-any.whl", hash = "sha256:d8ae43e8fe34060fcd5c3f494e0b7652b7774beabe94568a2283d0881e94d489"},
+ {file = "testcontainers-4.8.1.tar.gz", hash = "sha256:5ded4820b7227ad526857eb3caaafcabce1bbac05d22ad194849b136ffae3cb0"},
+]
+
+[package.dependencies]
+docker = "*"
+typing-extensions = "*"
+urllib3 = "*"
+wrapt = "*"
+
+[package.extras]
+arangodb = ["python-arango (>=7.8,<8.0)"]
+aws = ["boto3", "httpx"]
+azurite = ["azure-storage-blob (>=12.19,<13.0)"]
+chroma = ["chromadb-client"]
+clickhouse = ["clickhouse-driver"]
+cosmosdb = ["azure-cosmos"]
+db2 = ["ibm_db_sa", "sqlalchemy"]
+generic = ["httpx", "redis"]
+google = ["google-cloud-datastore (>=2)", "google-cloud-pubsub (>=2)"]
+influxdb = ["influxdb", "influxdb-client"]
+k3s = ["kubernetes", "pyyaml"]
+keycloak = ["python-keycloak"]
+localstack = ["boto3"]
+mailpit = ["cryptography"]
+minio = ["minio"]
+mongodb = ["pymongo"]
+mssql = ["pymssql", "sqlalchemy"]
+mysql = ["pymysql[rsa]", "sqlalchemy"]
+nats = ["nats-py"]
+neo4j = ["neo4j"]
+opensearch = ["opensearch-py"]
+oracle = ["oracledb", "sqlalchemy"]
+oracle-free = ["oracledb", "sqlalchemy"]
+qdrant = ["qdrant-client"]
+rabbitmq = ["pika"]
+redis = ["redis"]
+registry = ["bcrypt"]
+scylla = ["cassandra-driver (==3.29.1)"]
+selenium = ["selenium"]
+sftp = ["cryptography"]
+test-module-import = ["httpx"]
+trino = ["trino"]
+weaviate = ["weaviate-client (>=4.5.4,<5.0.0)"]
+
+[[package]]
+name = "text-unidecode"
+version = "1.3"
+description = "The most basic Text::Unidecode port"
+optional = false
+python-versions = "*"
+files = [
+ {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
+ {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
+]
+
[[package]]
name = "toml"
version = "0.10.2"
@@ -4443,13 +5734,13 @@ files = [
[[package]]
name = "types-pyyaml"
-version = "6.0.12.20240808"
+version = "6.0.12.20240917"
description = "Typing stubs for PyYAML"
optional = false
python-versions = ">=3.8"
files = [
- {file = "types-PyYAML-6.0.12.20240808.tar.gz", hash = "sha256:b8f76ddbd7f65440a8bda5526a9607e4c7a322dc2f8e1a8c405644f9a6f4b9af"},
- {file = "types_PyYAML-6.0.12.20240808-py3-none-any.whl", hash = "sha256:deda34c5c655265fc517b546c902aa6eed2ef8d3e921e4765fe606fe2afe8d35"},
+ {file = "types-PyYAML-6.0.12.20240917.tar.gz", hash = "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587"},
+ {file = "types_PyYAML-6.0.12.20240917-py3-none-any.whl", hash = "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570"},
]
[[package]]
@@ -4496,6 +5787,23 @@ files = [
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
]
+[[package]]
+name = "tzlocal"
+version = "5.2"
+description = "tzinfo object for the local timezone"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"},
+ {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"},
+]
+
+[package.dependencies]
+tzdata = {version = "*", markers = "platform_system == \"Windows\""}
+
+[package.extras]
+devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"]
+
[[package]]
name = "ujson"
version = "5.10.0"
@@ -4585,13 +5893,13 @@ files = [
[[package]]
name = "urllib3"
-version = "2.2.2"
+version = "2.2.3"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.8"
files = [
- {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
- {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
+ {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
+ {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
]
[package.extras]
@@ -4672,13 +5980,13 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)"
[[package]]
name = "virtualenv"
-version = "20.26.4"
+version = "20.26.5"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.7"
files = [
- {file = "virtualenv-20.26.4-py3-none-any.whl", hash = "sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55"},
- {file = "virtualenv-20.26.4.tar.gz", hash = "sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c"},
+ {file = "virtualenv-20.26.5-py3-none-any.whl", hash = "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6"},
+ {file = "virtualenv-20.26.5.tar.gz", hash = "sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4"},
]
[package.dependencies]
@@ -4798,97 +6106,97 @@ files = [
[[package]]
name = "websockets"
-version = "13.0.1"
+version = "13.1"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
optional = false
python-versions = ">=3.8"
files = [
- {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f"},
- {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c"},
- {file = "websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f"},
- {file = "websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543"},
- {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d"},
- {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f"},
- {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8"},
- {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b"},
- {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448"},
- {file = "websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3"},
- {file = "websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0"},
- {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7"},
- {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4"},
- {file = "websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2"},
- {file = "websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0"},
- {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e"},
- {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462"},
- {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501"},
- {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418"},
- {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df"},
- {file = "websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f"},
- {file = "websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075"},
- {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a"},
- {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956"},
- {file = "websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af"},
- {file = "websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf"},
- {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c"},
- {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4"},
- {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab"},
- {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d"},
- {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237"},
- {file = "websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185"},
- {file = "websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99"},
- {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa"},
- {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231"},
- {file = "websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9"},
- {file = "websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75"},
- {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553"},
- {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920"},
- {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329"},
- {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7"},
- {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2"},
- {file = "websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb"},
- {file = "websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b"},
- {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b74593e9acf18ea5469c3edaa6b27fa7ecf97b30e9dabd5a94c4c940637ab96e"},
- {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:132511bfd42e77d152c919147078460c88a795af16b50e42a0bd14f0ad71ddd2"},
- {file = "websockets-13.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:165bedf13556f985a2aa064309baa01462aa79bf6112fbd068ae38993a0e1f1b"},
- {file = "websockets-13.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e801ca2f448850685417d723ec70298feff3ce4ff687c6f20922c7474b4746ae"},
- {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30d3a1f041360f029765d8704eae606781e673e8918e6b2c792e0775de51352f"},
- {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67648f5e50231b5a7f6d83b32f9c525e319f0ddc841be0de64f24928cd75a603"},
- {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4f0426d51c8f0926a4879390f53c7f5a855e42d68df95fff6032c82c888b5f36"},
- {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ef48e4137e8799998a343706531e656fdec6797b80efd029117edacb74b0a10a"},
- {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:249aab278810bee585cd0d4de2f08cfd67eed4fc75bde623be163798ed4db2eb"},
- {file = "websockets-13.0.1-cp38-cp38-win32.whl", hash = "sha256:06c0a667e466fcb56a0886d924b5f29a7f0886199102f0a0e1c60a02a3751cb4"},
- {file = "websockets-13.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f3cf6d6ec1142412d4535adabc6bd72a63f5f148c43fe559f06298bc21953c9"},
- {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa082ea38d5de51dd409434edc27c0dcbd5fed2b09b9be982deb6f0508d25bc"},
- {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a365bcb7be554e6e1f9f3ed64016e67e2fa03d7b027a33e436aecf194febb63"},
- {file = "websockets-13.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10a0dc7242215d794fb1918f69c6bb235f1f627aaf19e77f05336d147fce7c37"},
- {file = "websockets-13.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59197afd478545b1f73367620407b0083303569c5f2d043afe5363676f2697c9"},
- {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d20516990d8ad557b5abeb48127b8b779b0b7e6771a265fa3e91767596d7d97"},
- {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a2e272d067030048e1fe41aa1ec8cfbbaabce733b3d634304fa2b19e5c897f"},
- {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad327ac80ba7ee61da85383ca8822ff808ab5ada0e4a030d66703cc025b021c4"},
- {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:518f90e6dd089d34eaade01101fd8a990921c3ba18ebbe9b0165b46ebff947f0"},
- {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68264802399aed6fe9652e89761031acc734fc4c653137a5911c2bfa995d6d6d"},
- {file = "websockets-13.0.1-cp39-cp39-win32.whl", hash = "sha256:a5dc0c42ded1557cc7c3f0240b24129aefbad88af4f09346164349391dea8e58"},
- {file = "websockets-13.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b448a0690ef43db5ef31b3a0d9aea79043882b4632cfc3eaab20105edecf6097"},
- {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89"},
- {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad"},
- {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e"},
- {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc"},
- {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333"},
- {file = "websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32"},
- {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f40de079779acbcdbb6ed4c65af9f018f8b77c5ec4e17a4b737c05c2db554491"},
- {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e4ba642fc87fa532bac07e5ed7e19d56940b6af6a8c61d4429be48718a380f"},
- {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a02b0161c43cc9e0232711eff846569fad6ec836a7acab16b3cf97b2344c060"},
- {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa74a45d4cdc028561a7d6ab3272c8b3018e23723100b12e58be9dfa5a24491"},
- {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00fd961943b6c10ee6f0b1130753e50ac5dcd906130dcd77b0003c3ab797d026"},
- {file = "websockets-13.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d93572720d781331fb10d3da9ca1067817d84ad1e7c31466e9f5e59965618096"},
- {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71e6e5a3a3728886caee9ab8752e8113670936a193284be9d6ad2176a137f376"},
- {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c4a6343e3b0714e80da0b0893543bf9a5b5fa71b846ae640e56e9abc6fbc4c83"},
- {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a678532018e435396e37422a95e3ab87f75028ac79570ad11f5bf23cd2a7d8c"},
- {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6716c087e4aa0b9260c4e579bb82e068f84faddb9bfba9906cb87726fa2e870"},
- {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e33505534f3f673270dd67f81e73550b11de5b538c56fe04435d63c02c3f26b5"},
- {file = "websockets-13.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acab3539a027a85d568c2573291e864333ec9d912675107d6efceb7e2be5d980"},
- {file = "websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817"},
- {file = "websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e"},
+ {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"},
+ {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"},
+ {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"},
+ {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"},
+ {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"},
+ {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"},
+ {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"},
+ {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"},
+ {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"},
+ {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"},
+ {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"},
+ {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"},
+ {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"},
+ {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"},
+ {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"},
+ {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"},
+ {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"},
+ {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"},
+ {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"},
+ {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"},
+ {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"},
+ {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"},
+ {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"},
+ {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"},
+ {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"},
+ {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"},
+ {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"},
+ {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"},
+ {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"},
+ {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"},
+ {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"},
+ {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"},
+ {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"},
+ {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"},
+ {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"},
+ {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"},
+ {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"},
+ {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"},
+ {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"},
+ {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"},
+ {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"},
+ {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"},
+ {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"},
+ {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"},
+ {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"},
+ {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"},
+ {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"},
+ {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"},
+ {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"},
+ {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"},
+ {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"},
+ {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"},
+ {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"},
+ {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"},
+ {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"},
+ {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"},
+ {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"},
+ {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"},
+ {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"},
+ {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"},
+ {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"},
+ {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"},
+ {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"},
+ {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"},
+ {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"},
+ {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"},
+ {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"},
+ {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"},
+ {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"},
+ {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"},
+ {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"},
+ {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"},
+ {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"},
+ {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"},
+ {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"},
+ {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"},
+ {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"},
+ {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"},
+ {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"},
+ {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"},
+ {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"},
+ {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"},
+ {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"},
+ {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"},
+ {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"},
+ {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"},
]
[[package]]
@@ -5007,103 +6315,103 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"]
[[package]]
name = "yarl"
-version = "1.11.0"
+version = "1.11.1"
description = "Yet another URL library"
optional = false
python-versions = ">=3.8"
files = [
- {file = "yarl-1.11.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0a657db1b9982f3dac0e360614d0e8945d2873da6e681fb7fca23ef1c3eb37f8"},
- {file = "yarl-1.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:65a1a05efca52b102691e64db5fcf973030a1c88fee393804ff91f99c95a6e74"},
- {file = "yarl-1.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f4cb417d380e2d77961eecec75aaaf6f7ab14e6de26eb3a498f498029a6556a1"},
- {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8aee7c8378c6aa3103b99d1eb9995268ef730fa9f88ea68b9eee4341e204eec9"},
- {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84624db40e2358cfd5cf2558b1aaffd93366d27ee32228a97785f2ec87d44a17"},
- {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a596bb15e036952549871a4ccd2205679902dc7f241e3ced6b2ab2e44c55795"},
- {file = "yarl-1.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9d4d2cc4b076c8ad0175a15ee9482a387b3303c97d4b71062db7356b2ac04c7"},
- {file = "yarl-1.11.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f8bc849004122591104793a576e9c747b0e5d9486d6a30225521b817255748"},
- {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e38176a559edde0cfff4b663791a007a5f9f90c73aee1d6f7ddbcf6bfb7287b3"},
- {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:706ac0f77b45e9e0278ec6c98929764e119d3ce3136792b6475e7ae961da53ec"},
- {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:48bac099586cf75ae5837b0ac17a674450d01f451f38afcb02acfc940110b60b"},
- {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:540fd5f62fe21f3d1d9efe8af5c4d9dbbb184ce03ce95acb0289500e46215dd2"},
- {file = "yarl-1.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05ab59db0bb64e847972373c5cda8924e6605480f6b13cc04573fa0d87bfc637"},
- {file = "yarl-1.11.0-cp310-cp310-win32.whl", hash = "sha256:ddab47748933ac9cf5f29d6e9e2e2060cff40b2751d02c55129661ea4e577152"},
- {file = "yarl-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:976d02274e6d88b24c7131e7b26a083412b2592f2bbcef53d3b00b2508cad26c"},
- {file = "yarl-1.11.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:39e3087e1ef70862de81e22af9eb299faee580f41673ef92829949022791b521"},
- {file = "yarl-1.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7fd535cc41b81a566ad347081b671ab5c7e5f5b6a15526d85b4e748baf065cf0"},
- {file = "yarl-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f7cc02d8e9a612174869f4b983f159e87659096f7e2dc1fe9effd9902e408739"},
- {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f391ccf4b1b1e0ba4880075ba337d41a619a5350f67053927f67ebe764bf44"},
- {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c19a0d95943bb2c914b4e71043803be34bc75c08c4a6ca232bdc649a1e9ef1b"},
- {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ead4d89eade0e09b8ef97877664abb0e2e8704787db5564f83658fdee5c36497"},
- {file = "yarl-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:195f7791bc23d5f2480efe53f935daf8a61661000dfbfbdd70dbd06397594fff"},
- {file = "yarl-1.11.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a7905e662665ca8e058635377522bc3c98bdb873be761ff42c86eb72b03914"},
- {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:53c80b1927b75aed208d7fd965a3a705dc8c1db4d50b9112418fa0f7784363e6"},
- {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:11af21bbf807688d49b7d4915bb28cbc2e3aa028a2ee194738477eabcc413c65"},
- {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:732d56da00ea7a5da4f0d15adbbd22dcb37da7825510aafde40112e53f6baa52"},
- {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7bd54d79025b59d1dc5fb26a09734d6a9cc651a04bc381966ed264b28331a168"},
- {file = "yarl-1.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aacd62ff67efd54cb18cea2aa7ae4fb83cfbca19a07055d4777266b70561defe"},
- {file = "yarl-1.11.0-cp311-cp311-win32.whl", hash = "sha256:68e14ae71e5b51c8282ae5db53ccb3baffc40e1551370a8a2361f1c1d8a0bf8c"},
- {file = "yarl-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:3ade2265716667b6bd4123d6f684b5f7cf4a8d83dcf1d5581ac44643466bb00a"},
- {file = "yarl-1.11.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6e73dab98e3c3b5441720153e72a5f28e717aac2d22f1ec4b08ef33417d9987e"},
- {file = "yarl-1.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4a0d090d296ced05edfe29c6ff34869412fa6a97d0928c12b00939c4842884cd"},
- {file = "yarl-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d29e446cfb0a82d3df7745968b9fa286665a9be8b4d68de46bcc32d917cb218e"},
- {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8dc0efcf8266ecfe057b95e01f43eb62516196a4bbf3918fd1dcb8d0dc0dff"},
- {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:202f5ec49ff163dcc767426deb55020a28078e61d6bbe1f80331d92bca53b236"},
- {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8055b0d78ce1cafa657c4b455e22661e8d3b2834de66a0753c3567da47fcc4aa"},
- {file = "yarl-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ed3c7f64e820959d7f682ec2f559b4f4df723dc09df619d269853a4214a4b4"},
- {file = "yarl-1.11.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2371510367d39d74997acfdcd1dead17938c79c99365482821627f7838a8eba0"},
- {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e24bb6a8be89ccc3ce8c47e8940fdfcb7429e9efbf65ce6fa3e7d122fcf0bcf0"},
- {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:18ec42da256cfcb9b4cd5d253e04c291f69911a5228d1438a7d431c15ba0ae40"},
- {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:418eeb8f228ea36c368bf6782ebd6016ecebfb1a8b90145ef6726ffcbba65ef8"},
- {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:07e8cfb1dd7669a129f8fd5df1da65efa73aea77582bde2a3a837412e2863543"},
- {file = "yarl-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c458483711d393dad51340505c3fab3194748fd06bab311d2f8b5b7a7349e9a"},
- {file = "yarl-1.11.0-cp312-cp312-win32.whl", hash = "sha256:5b008c3127382503e7a1e12b4c3a3236e3dd833a4c62a066f4a0fbd650c655d2"},
- {file = "yarl-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc94be7472b9f88d7441340534a3ecae05c86ccfec7ba75ce5b6e4778b2bfc6e"},
- {file = "yarl-1.11.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a45e51ba3777031e0b20c1e7ab59114ed4e1884b3c1db48962c1d8d08aefb418"},
- {file = "yarl-1.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:765128029218eade3a01187cdd7f375977cc827505ed31828196c8ae9b622928"},
- {file = "yarl-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2516e238daf0339c8ac4dfab9d7cda9afad652ff073517f200d653d5d8371f7e"},
- {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d10be62bee117f05b1ad75a6c2538ca9e5367342dc8a4f3c206c87dadbc1189c"},
- {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50ceaeda771ee3e382291168c90c7ede62b63ecf3e181024bcfeb35c0ea6c84f"},
- {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a601c99fc20fd0eea84e7bc0dc9e7f196f55a0ded67242d724988c754295538"},
- {file = "yarl-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42ff79371614764fc0a4ab8eaba9adb493bf9ad856e2a4664f6c754fc907a903"},
- {file = "yarl-1.11.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93fca4c9f88c17ead902b3f3285b2d039fc8f26d117e1441973ba64315109b54"},
- {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e7dddf5f41395c84fc59e0ed5493b24bfeb39fb04823e880b52c8c55085d4695"},
- {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ea501ea07e14ba6364ff2621bfc8b2381e5b1e10353927fa9a607057fd2b98e5"},
- {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a4f7e470f2c9c8b8774a5bda72adfb8e9dc4ec32311fe9bdaa4921e36cf6659b"},
- {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:361fdb3993431157302b7104d525092b5df4d7d346df5a5ffeee2d1ca8e0d15b"},
- {file = "yarl-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e300eaf5e0329ad31b3d53e2f3d26b4b6dff1217207c6ab1d4212967b54b2185"},
- {file = "yarl-1.11.0-cp313-cp313-win32.whl", hash = "sha256:f1e2d4ce72e06e38a16da3e9c24a0520dbc19018a69ef6ed57b6b38527cb275c"},
- {file = "yarl-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:fa9de2f87be58f714a230bd1f3ef3aad1ed65c9931146e3fc55f85fcbe6bacc3"},
- {file = "yarl-1.11.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:24da0b38274727fe9266d09229987e7f0efdb97beb94c0bb2d327d65f112e78d"},
- {file = "yarl-1.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0310eb2e63872de66047e05ad9982f2e53ad6405dc42fa60d7cc670bf6ca8aa8"},
- {file = "yarl-1.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:52433604340a4ab3d1f32281c6eb9ad9b47c99435b4212f763121bf7348c8c00"},
- {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98e2eb182d59f0845a79434003f94b4f61cd69465248f9388c2e5bf2191c9f7f"},
- {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3dd10f0fe0e0f659926c1da791de5bef05fd48974ad74618c9168e302e2b7cc"},
- {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:121d3798e4bb35a4321b2422cb887f80ea39f94bf52f0eb5cb2c168bb0043c9b"},
- {file = "yarl-1.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8bbac56c80610dd659ace534765d7bcd2488f6600023f6984f35108b2b3f4f0"},
- {file = "yarl-1.11.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79d420399f0e82e302236a762d8b8ceec89761ce3b30c83ac1d4d6e29f811444"},
- {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:03a726fb50588307dfe1d233b67535d493fb0bb157bdbfda6bb34e04189f2f57"},
- {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9057f5de2fade7440e6db358913bc7ae8de43ba72c83cf95420a1fc1a6c6b59e"},
- {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:6471d747d0ac8059895e66d32ca8630c8db5b572ca7763150d0927eaa257df67"},
- {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:d97cb22ad380850754fa16ef8d490d9340d8573d81f73429f3975e8e87db0586"},
- {file = "yarl-1.11.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fe78dec8caeda1e7b353cbd8aa0cc5a5bc182b22998d64ec8fa9ee59c898ab3b"},
- {file = "yarl-1.11.0-cp38-cp38-win32.whl", hash = "sha256:7ff371002fbbb79613269d76a2932c99979dac15fac30107064ef70d25f35474"},
- {file = "yarl-1.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:4fa9d762eee63eed767895d68b994c58e29f809292a4d0fca483e9cc6fdc22c8"},
- {file = "yarl-1.11.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4ae63bc65e5bf8843bd1eca46e75eaa9eb157e0312fb362123181512892daad8"},
- {file = "yarl-1.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3d1bd3262e00043907e0a6d7d4f7b7a4815281acc25699a2384552870c79f1f0"},
- {file = "yarl-1.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c58656c2e0b41b5d325130b8da4f8e216aad10029e7de5c523a6be25faa9fe8"},
- {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9425c333575fce5e0fb414b766492c6ba4aa335ef910a7540dbdefe58a78232e"},
- {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dc66e2420e1e282105071934883bbb9c37c16901b5b8aa0a8aee370b477eac6"},
- {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2949067359d1ef5bf3228c7f1deb102c209832a13df5419239f99449bc1d3fa9"},
- {file = "yarl-1.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006fe73f851cf20b9986b3b4cc15239795bd5da9c3fda76bb3e043da5bec4ff"},
- {file = "yarl-1.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:969ad4ee3892e893471b6572bbf2bbb091f93e7c81de25d6b3a5c0a5126e5ccb"},
- {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c9fbe9dc6ee8bfe1af34137e3add6f0e49799dd5467dd6af189d27616879161e"},
- {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69a45c711fea9b783b592a75f26f6dc59b2e4a923b97bf6eec357566fcb1d922"},
- {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1a29b82c42a7791ffe53ee6dfbf29acc61ea7ec05643dcacc50510ed6187b897"},
- {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ed0c090f00c3fc024f7b0799cab9dd7c419fcd8f1a00634d1f9952bab7e7bfb2"},
- {file = "yarl-1.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:31df9d9b3fe6e15decee629fc7976a5fb21eaa39e290f60e57e1d422827194c6"},
- {file = "yarl-1.11.0-cp39-cp39-win32.whl", hash = "sha256:fcb7c36ba8b663a5900e6d40533f0e698ba0f38f744aad5410d4e38129e41a70"},
- {file = "yarl-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:c6c0d640bad721834a737e25267fb71d296684ada21ca7d5ad2e63da7b73f1b7"},
- {file = "yarl-1.11.0-py3-none-any.whl", hash = "sha256:03717a6627e55934b2a1d9caf24f299b461a2e8d048a90920f42ad5c20ae1b82"},
- {file = "yarl-1.11.0.tar.gz", hash = "sha256:f86f4f4a57a29ef08fa70c4667d04c5e3ba513500da95586208b285437cb9592"},
+ {file = "yarl-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:400cd42185f92de559d29eeb529e71d80dfbd2f45c36844914a4a34297ca6f00"},
+ {file = "yarl-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8258c86f47e080a258993eed877d579c71da7bda26af86ce6c2d2d072c11320d"},
+ {file = "yarl-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2164cd9725092761fed26f299e3f276bb4b537ca58e6ff6b252eae9631b5c96e"},
+ {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08ea567c16f140af8ddc7cb58e27e9138a1386e3e6e53982abaa6f2377b38cc"},
+ {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:768ecc550096b028754ea28bf90fde071c379c62c43afa574edc6f33ee5daaec"},
+ {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2909fa3a7d249ef64eeb2faa04b7957e34fefb6ec9966506312349ed8a7e77bf"},
+ {file = "yarl-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01a8697ec24f17c349c4f655763c4db70eebc56a5f82995e5e26e837c6eb0e49"},
+ {file = "yarl-1.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e286580b6511aac7c3268a78cdb861ec739d3e5a2a53b4809faef6b49778eaff"},
+ {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4179522dc0305c3fc9782549175c8e8849252fefeb077c92a73889ccbcd508ad"},
+ {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27fcb271a41b746bd0e2a92182df507e1c204759f460ff784ca614e12dd85145"},
+ {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f61db3b7e870914dbd9434b560075e0366771eecbe6d2b5561f5bc7485f39efd"},
+ {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c92261eb2ad367629dc437536463dc934030c9e7caca861cc51990fe6c565f26"},
+ {file = "yarl-1.11.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d95b52fbef190ca87d8c42f49e314eace4fc52070f3dfa5f87a6594b0c1c6e46"},
+ {file = "yarl-1.11.1-cp310-cp310-win32.whl", hash = "sha256:489fa8bde4f1244ad6c5f6d11bb33e09cf0d1d0367edb197619c3e3fc06f3d91"},
+ {file = "yarl-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:476e20c433b356e16e9a141449f25161e6b69984fb4cdbd7cd4bd54c17844998"},
+ {file = "yarl-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:946eedc12895873891aaceb39bceb484b4977f70373e0122da483f6c38faaa68"},
+ {file = "yarl-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:21a7c12321436b066c11ec19c7e3cb9aec18884fe0d5b25d03d756a9e654edfe"},
+ {file = "yarl-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c35f493b867912f6fda721a59cc7c4766d382040bdf1ddaeeaa7fa4d072f4675"},
+ {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25861303e0be76b60fddc1250ec5986c42f0a5c0c50ff57cc30b1be199c00e63"},
+ {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4b53f73077e839b3f89c992223f15b1d2ab314bdbdf502afdc7bb18e95eae27"},
+ {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:327c724b01b8641a1bf1ab3b232fb638706e50f76c0b5bf16051ab65c868fac5"},
+ {file = "yarl-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4307d9a3417eea87715c9736d050c83e8c1904e9b7aada6ce61b46361b733d92"},
+ {file = "yarl-1.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a28bed68ab8fb7e380775f0029a079f08a17799cb3387a65d14ace16c12e2b"},
+ {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:067b961853c8e62725ff2893226fef3d0da060656a9827f3f520fb1d19b2b68a"},
+ {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8215f6f21394d1f46e222abeb06316e77ef328d628f593502d8fc2a9117bde83"},
+ {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:498442e3af2a860a663baa14fbf23fb04b0dd758039c0e7c8f91cb9279799bff"},
+ {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:69721b8effdb588cb055cc22f7c5105ca6fdaa5aeb3ea09021d517882c4a904c"},
+ {file = "yarl-1.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e969fa4c1e0b1a391f3fcbcb9ec31e84440253325b534519be0d28f4b6b533e"},
+ {file = "yarl-1.11.1-cp311-cp311-win32.whl", hash = "sha256:7d51324a04fc4b0e097ff8a153e9276c2593106a811704025bbc1d6916f45ca6"},
+ {file = "yarl-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:15061ce6584ece023457fb8b7a7a69ec40bf7114d781a8c4f5dcd68e28b5c53b"},
+ {file = "yarl-1.11.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a4264515f9117be204935cd230fb2a052dd3792789cc94c101c535d349b3dab0"},
+ {file = "yarl-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f41fa79114a1d2eddb5eea7b912d6160508f57440bd302ce96eaa384914cd265"},
+ {file = "yarl-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02da8759b47d964f9173c8675710720b468aa1c1693be0c9c64abb9d8d9a4867"},
+ {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9361628f28f48dcf8b2f528420d4d68102f593f9c2e592bfc842f5fb337e44fd"},
+ {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b91044952da03b6f95fdba398d7993dd983b64d3c31c358a4c89e3c19b6f7aef"},
+ {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74db2ef03b442276d25951749a803ddb6e270d02dda1d1c556f6ae595a0d76a8"},
+ {file = "yarl-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e975a2211952a8a083d1b9d9ba26472981ae338e720b419eb50535de3c02870"},
+ {file = "yarl-1.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aef97ba1dd2138112890ef848e17d8526fe80b21f743b4ee65947ea184f07a2"},
+ {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7915ea49b0c113641dc4d9338efa9bd66b6a9a485ffe75b9907e8573ca94b84"},
+ {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:504cf0d4c5e4579a51261d6091267f9fd997ef58558c4ffa7a3e1460bd2336fa"},
+ {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3de5292f9f0ee285e6bd168b2a77b2a00d74cbcfa420ed078456d3023d2f6dff"},
+ {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a34e1e30f1774fa35d37202bbeae62423e9a79d78d0874e5556a593479fdf239"},
+ {file = "yarl-1.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66b63c504d2ca43bf7221a1f72fbe981ff56ecb39004c70a94485d13e37ebf45"},
+ {file = "yarl-1.11.1-cp312-cp312-win32.whl", hash = "sha256:a28b70c9e2213de425d9cba5ab2e7f7a1c8ca23a99c4b5159bf77b9c31251447"},
+ {file = "yarl-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:17b5a386d0d36fb828e2fb3ef08c8829c1ebf977eef88e5367d1c8c94b454639"},
+ {file = "yarl-1.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1fa2e7a406fbd45b61b4433e3aa254a2c3e14c4b3186f6e952d08a730807fa0c"},
+ {file = "yarl-1.11.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:750f656832d7d3cb0c76be137ee79405cc17e792f31e0a01eee390e383b2936e"},
+ {file = "yarl-1.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b8486f322d8f6a38539136a22c55f94d269addb24db5cb6f61adc61eabc9d93"},
+ {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fce4da3703ee6048ad4138fe74619c50874afe98b1ad87b2698ef95bf92c96d"},
+ {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed653638ef669e0efc6fe2acb792275cb419bf9cb5c5049399f3556995f23c7"},
+ {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18ac56c9dd70941ecad42b5a906820824ca72ff84ad6fa18db33c2537ae2e089"},
+ {file = "yarl-1.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:688654f8507464745ab563b041d1fb7dab5d9912ca6b06e61d1c4708366832f5"},
+ {file = "yarl-1.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4973eac1e2ff63cf187073cd4e1f1148dcd119314ab79b88e1b3fad74a18c9d5"},
+ {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:964a428132227edff96d6f3cf261573cb0f1a60c9a764ce28cda9525f18f7786"},
+ {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6d23754b9939cbab02c63434776df1170e43b09c6a517585c7ce2b3d449b7318"},
+ {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c2dc4250fe94d8cd864d66018f8344d4af50e3758e9d725e94fecfa27588ff82"},
+ {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09696438cb43ea6f9492ef237761b043f9179f455f405279e609f2bc9100212a"},
+ {file = "yarl-1.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:999bfee0a5b7385a0af5ffb606393509cfde70ecca4f01c36985be6d33e336da"},
+ {file = "yarl-1.11.1-cp313-cp313-win32.whl", hash = "sha256:ce928c9c6409c79e10f39604a7e214b3cb69552952fbda8d836c052832e6a979"},
+ {file = "yarl-1.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:501c503eed2bb306638ccb60c174f856cc3246c861829ff40eaa80e2f0330367"},
+ {file = "yarl-1.11.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dae7bd0daeb33aa3e79e72877d3d51052e8b19c9025ecf0374f542ea8ec120e4"},
+ {file = "yarl-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3ff6b1617aa39279fe18a76c8d165469c48b159931d9b48239065767ee455b2b"},
+ {file = "yarl-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3257978c870728a52dcce8c2902bf01f6c53b65094b457bf87b2644ee6238ddc"},
+ {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f351fa31234699d6084ff98283cb1e852270fe9e250a3b3bf7804eb493bd937"},
+ {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8aef1b64da41d18026632d99a06b3fefe1d08e85dd81d849fa7c96301ed22f1b"},
+ {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7175a87ab8f7fbde37160a15e58e138ba3b2b0e05492d7351314a250d61b1591"},
+ {file = "yarl-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba444bdd4caa2a94456ef67a2f383710928820dd0117aae6650a4d17029fa25e"},
+ {file = "yarl-1.11.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ea9682124fc062e3d931c6911934a678cb28453f957ddccf51f568c2f2b5e05"},
+ {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8418c053aeb236b20b0ab8fa6bacfc2feaaf7d4683dd96528610989c99723d5f"},
+ {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:61a5f2c14d0a1adfdd82258f756b23a550c13ba4c86c84106be4c111a3a4e413"},
+ {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f3a6d90cab0bdf07df8f176eae3a07127daafcf7457b997b2bf46776da2c7eb7"},
+ {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:077da604852be488c9a05a524068cdae1e972b7dc02438161c32420fb4ec5e14"},
+ {file = "yarl-1.11.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:15439f3c5c72686b6c3ff235279630d08936ace67d0fe5c8d5bbc3ef06f5a420"},
+ {file = "yarl-1.11.1-cp38-cp38-win32.whl", hash = "sha256:238a21849dd7554cb4d25a14ffbfa0ef380bb7ba201f45b144a14454a72ffa5a"},
+ {file = "yarl-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:67459cf8cf31da0e2cbdb4b040507e535d25cfbb1604ca76396a3a66b8ba37a6"},
+ {file = "yarl-1.11.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:884eab2ce97cbaf89f264372eae58388862c33c4f551c15680dd80f53c89a269"},
+ {file = "yarl-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a336eaa7ee7e87cdece3cedb395c9657d227bfceb6781295cf56abcd3386a26"},
+ {file = "yarl-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87f020d010ba80a247c4abc335fc13421037800ca20b42af5ae40e5fd75e7909"},
+ {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:637c7ddb585a62d4469f843dac221f23eec3cbad31693b23abbc2c366ad41ff4"},
+ {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48dfd117ab93f0129084577a07287376cc69c08138694396f305636e229caa1a"},
+ {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e0ae31fb5ccab6eda09ba1494e87eb226dcbd2372dae96b87800e1dcc98804"},
+ {file = "yarl-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f46f81501160c28d0c0b7333b4f7be8983dbbc161983b6fb814024d1b4952f79"},
+ {file = "yarl-1.11.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:04293941646647b3bfb1719d1d11ff1028e9c30199509a844da3c0f5919dc520"},
+ {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:250e888fa62d73e721f3041e3a9abf427788a1934b426b45e1b92f62c1f68366"},
+ {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e8f63904df26d1a66aabc141bfd258bf738b9bc7bc6bdef22713b4f5ef789a4c"},
+ {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:aac44097d838dda26526cffb63bdd8737a2dbdf5f2c68efb72ad83aec6673c7e"},
+ {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:267b24f891e74eccbdff42241c5fb4f974de2d6271dcc7d7e0c9ae1079a560d9"},
+ {file = "yarl-1.11.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6907daa4b9d7a688063ed098c472f96e8181733c525e03e866fb5db480a424df"},
+ {file = "yarl-1.11.1-cp39-cp39-win32.whl", hash = "sha256:14438dfc5015661f75f85bc5adad0743678eefee266ff0c9a8e32969d5d69f74"},
+ {file = "yarl-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:94d0caaa912bfcdc702a4204cd5e2bb01eb917fc4f5ea2315aa23962549561b0"},
+ {file = "yarl-1.11.1-py3-none-any.whl", hash = "sha256:72bf26f66456baa0584eff63e44545c9f0eaed9b73cb6601b647c91f14c11f38"},
+ {file = "yarl-1.11.1.tar.gz", hash = "sha256:1bb2d9e212fb7449b8fb73bc461b51eaa17cc8430b4a87d87be7b25052d92f53"},
]
[package.dependencies]
@@ -5112,13 +6420,13 @@ multidict = ">=4.0"
[[package]]
name = "zipp"
-version = "3.20.1"
+version = "3.20.2"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.8"
files = [
- {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"},
- {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"},
+ {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"},
+ {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"},
]
[package.extras]
@@ -5201,4 +6509,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata]
lock-version = "2.0"
python-versions = "^3.10, < 3.13"
-content-hash = "b2cd3d01d16769e9521a97ae561aff50f1799a9814eee027306b81e972a451ab"
+content-hash = "b0d21b2cc1781a650f03881d47d174e7655c7302a86b3380965a89e2b01bb5d8"
diff --git a/pyproject.toml b/pyproject.toml
index 679ed29034..43ed310d9b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "infrahub"
-version = "0.16.2"
+version = "1.0.0-dev0"
description = "Infrahub is taking a new approach to Infrastructure Management by providing a new generation of datastore to organize and control all the data that defines how an infrastructure should run."
authors = ["OpsMill "]
readme = "README.md"
@@ -39,6 +39,7 @@ boto3 = "1.34.129"
email-validator = "~2.1"
redis = { version = "^5.0.0", extras = ["hiredis"] }
typer = "0.12.3"
+prefect = "3.0.3"
# Dependencies specific to the API Server
fastapi = "~0.112"
@@ -58,6 +59,7 @@ opentelemetry-exporter-otlp-proto-grpc = "^1.24.0"
opentelemetry-exporter-otlp-proto-http = "^1.24.0"
nats-py = "^2.7.2"
netaddr = "1.3.0"
+authlib = "1.3.2"
[tool.poetry.group.dev.dependencies]
yamllint = "*"
@@ -77,13 +79,16 @@ pre-commit = "^2.20.0"
types-toml = "*"
types-ujson = "*"
types-pyyaml = "*"
-ruff = "0.5.0"
+ruff = "0.6.6"
invoke = "2.2.0"
pytest-benchmark = "^4.0.0"
pytest-codspeed = "^2.2.0"
deepdiff = "^6.2"
polyfactory = "^2.16.2"
towncrier = "^24.8"
+pytest-env = "^1.1.3"
+testcontainers = "^4.8.1"
+pytest-timeout = "^2.3.1"
[tool.poetry.group.test-scale.dependencies]
locust = "^2.20.1"
@@ -96,6 +101,9 @@ infrahub = "infrahub.cli:app"
infrahub-git-credential = "infrahub.git_credential.helper:app"
infrahub-git-askpass = "infrahub.git_credential.askpass:app"
+[tool.poetry.plugins."prefect.collections"]
+"infrahubasync" = "infrahub.workers.infrahub_async"
+
[tool.coverage.run]
branch = true
@@ -143,6 +151,7 @@ disable = """,
too-many-return-statements,
unnecessary-comprehension,
multiple-statements,
+ self-assigning-variable,
"""
[tool.pylint.miscellaneous]
@@ -156,6 +165,8 @@ min-similarity-lines = 20
[tool.pytest.ini_options]
asyncio_mode = "auto"
+timeout = 300 # 5 minutes
+session_timeout = 1200 # 20 minutes
testpaths = ["tests"]
filterwarnings = [
"ignore:Module already imported so cannot be rewritten",
@@ -165,6 +176,10 @@ filterwarnings = [
addopts = "-vs --cov-report term-missing --cov-report xml --dist loadscope --junitxml=pytest-junit.xml"
junit_duration_report = "call"
+[tool.pytest_env]
+PREFECT_LOGGING_LEVEL = "CRITICAL"
+INFRAHUB_LOG_LEVEL = "CRITICAL"
+
[tool.mypy]
pretty = true
ignore_missing_imports = true
@@ -253,9 +268,14 @@ module = "infrahub.core.schema.basenode_schema"
ignore_errors = true
[[tool.mypy.overrides]]
-module = "infrahub.core.schema_manager"
+module = "infrahub.core.schema.schema_branch"
+ignore_errors = true
+
+[[tool.mypy.overrides]]
+module = "infrahub.core.schema.manager"
ignore_errors = true
+
[[tool.mypy.overrides]]
module = "infrahub.core.utils"
ignore_errors = true
@@ -312,23 +332,10 @@ ignore_errors = true
module = "infrahub.graphql.resolver"
ignore_errors = true
-[[tool.mypy.overrides]]
-module = "infrahub.graphql.schema"
-ignore_errors = true
-
[[tool.mypy.overrides]]
module = "infrahub.graphql.subscription"
ignore_errors = true
-
-[[tool.mypy.overrides]]
-module = "infrahub.graphql.types.attribute"
-ignore_errors = true
-
-[[tool.mypy.overrides]]
-module = "infrahub.graphql.types.mixin"
-ignore_errors = true
-
[[tool.mypy.overrides]]
module = "infrahub.graphql.types.standard_node"
ignore_errors = true
@@ -381,22 +388,6 @@ ignore_errors = true
module = "infrahub.message_bus.operations.schema.validator"
ignore_errors = true
-[[tool.mypy.overrides]]
-module = "infrahub.message_bus.operations.send.telemetry"
-ignore_errors = true
-
-[[tool.mypy.overrides]]
-module = "infrahub.message_bus.operations.send.webhook"
-ignore_errors = true
-
-[[tool.mypy.overrides]]
-module = "infrahub.message_bus.operations.trigger.ipam"
-ignore_errors = true
-
-[[tool.mypy.overrides]]
-module = "infrahub.test_data.dataset01"
-ignore_errors = true
-
[[tool.mypy.overrides]]
module = "infrahub.test_data.dataset03"
ignore_errors = true
@@ -456,6 +447,7 @@ select = [
"E", # pycodestyle errors
"EXE", # flake8-executable
"F", # pyflakes
+ "FURB", # refurb
"I", # isort-like checks
"ICN", # flake8-import-conventions
"INP", # flake8-no-pep420
@@ -467,7 +459,9 @@ select = [
"PYI", # flake8-pyi
"Q", # flake8-quotes
"RET", # flake8-return
+ "RUF", # Ruff specific rules
"S", # flake8-bandit
+ "SIM", # flake8-simplify
"TCH", # flake8-type-checking
"T10", # flake8-debugger
"UP", # pyupgrade
@@ -482,6 +476,7 @@ ignore = [
# like this so that we can reactivate them one by one. Alternatively ignored after further #
# investigation if they are deemed to not make sense. #
##################################################################################################
+ "ASYNC110", # Use `anyio.Event` instead of awaiting `anyio.sleep` in a `while` loop
"ASYNC230", # Async functions should not open files with blocking methods like `open`
"ASYNC251", # Async functions should not call `time.sleep`
"B007", # Loop control variable not used within loop body
@@ -492,6 +487,14 @@ ignore = [
"C403", # Unnecessary `list` comprehension (rewrite as a `set` comprehension)
"C409", # Unnecessary `list` literal passed to `tuple()` (rewrite as a `tuple` literal)
"C414", # Unnecessary `list` call within `sorted()`
+ "C420", # Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead
+ "E721", # Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
+ "FURB113", # Use `networks.extend(...)` instead of repeatedly calling `networks.append()`
+ "FURB116", # Replace `bin` call with f-string
+ "FURB118", # Use `operator.itemgetter(1)` instead of defining a lambda
+ "FURB140", # Use `itertools.starmap` instead of the generator
+ "FURB171", # Membership test against single-item container
+ "FURB192", # Prefer `min` over `sorted()` to compute the minimum value in a sequence
"N801", # Class name should use CapWords convention
"N802", # Function name should be lowercase
"N805", # First argument of a method should be named self
@@ -516,7 +519,6 @@ ignore = [
"PLR6301", # Method could be a function, class method, or static method
"PLW0603", # Using the global statement to update `SETTINGS` is discouraged
"PLW1508", # Invalid type for environment variable default; expected `str` or `None`
- "PLW3201", # Bad or misspelled dunder method name `__init_subclass_with_meta__`
"PTH100", # `os.path.abspath()` should be replaced by `Path.resolve()`
"PTH102", # `os.mkdir()` should be replaced by `Path.mkdir()`
"PTH103", # `os.makedirs()` should be replaced by `Path.mkdir(parents=True)`
@@ -530,17 +532,38 @@ ignore = [
"PTH118", # `os.path.join()` should be replaced by `Path` with `/` operator
"RET503", # Missing explicit `return` at the end of function able to return non-`None` value
"RET504", # Unnecessary assignment before `return` statement
+ "RUF005", # Consider `[*list(peers.values()), rfc5735]` instead of concatenation
+ "RUF006", # Store a reference to the return value of `asyncio.create_task`
+ "RUF010", # Use explicit conversion flag
+ "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
+ "RUF013", # PEP 484 prohibits implicit `Optional`
+ "RUF015", # Prefer `next(...)` over single element slice
+ "RUF021", # Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
+ "RUF027", # Possible f-string without an `f` prefix
+ "RUF029", # Function is declared `async`, but doesn't `await` or use `async` features.
"S101", # Use of `assert` detected
"S105", # Possible hardcoded password assigned to: "REGEX_PASSWORD"
"S108", # Probable insecure usage of temporary file or directory
"S202", # Uses of `tarfile.extractall()`
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
"S701", # By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True`
+ "SIM108", # Use ternary operator `markexpr = "not neo4j" if not markexpr else f"not neo4j and ({markexpr})"` instead of `if`-`else`-block
+ "SIM102", # Use a single `if` statement instead of nested `if` statements
+ "SIM103", # Return the condition `identifier in self.sub_by_id.keys()` directly
+ "SIM105", # Use `contextlib.suppress(SchemaNotFoundError)` instead of `try`-`except`-`pass`
+ "SIM110", # Use `return any(worktree.identifier == identifier for worktree in worktrees)` instead of `for` loop
+ "SIM114", # Combine `if` branches using logical `or` operator
+ "SIM115", # Use a context manager for opening files
+ "SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements
+ "SIM118", # Use `key in dict` instead of `key in dict.keys()`
+ "SIM201", # Use `backup_path.suffix != ".backup"` instead of `not backup_path.suffix == ".backup"`
+ "SIM300", # Yoda condition detected
+ "SIM401", # Use `property["items"].get("format", None)` instead of an `if` block
+ "SIM910", # Use `data.get("identifier")` instead of `data.get("identifier", None)`
"UP007", # Use X | Y for type annotations
"UP012", # Unnecessary call to encode as UTF-8
"UP018", # Unnecessary {literal_type} call (rewrite as a literal)
"UP031", # Use format specifiers instead of percent format
- "UP034", # Avoid extraneous parentheses
]
#https://docs.astral.sh/ruff/formatter/black/
@@ -560,6 +583,12 @@ max-line-length = 150
# Target max-complexity=10
max-complexity = 33
+[tool.ruff.lint.pylint]
+
+allow-dunder-method-names = [
+ "__init_subclass_with_meta__", # Dunder method used within Graphene
+]
+
[tool.ruff.lint.per-file-ignores]
"backend/infrahub/**.py" = [
@@ -567,17 +596,27 @@ max-complexity = 33
# Review and change the below later #
##################################################################################################
"ANN001", # Missing type annotation for function argument
- "ANN002", # Missing type annotation for `*args`
"ANN003", # Missing type annotation for `**kwargs`
- "ANN201", # Missing return type annotation for public function
- "ANN202", # Missing return type annotation for private function
"ANN204", # Missing return type annotation for special method
- "ANN206", # Missing return type annotation for classmethod
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
]
-"backend/infrahub/git/repository.py" = [
- "TCH003", # Pydantic needs UUID import to not only be available under TYPE_CHECKING clause
+"backend/infrahub/config.py" = [
+ "S323", # Allow users to create an SSL context that doesn't validate certificates
+]
+
+"backend/infrahub/graphql/mutations/**.py" = [
+ ##################################################################################################
+ # Review and change the below later #
+ ##################################################################################################
+ "ANN206", # Missing return type annotation for classmethod
+]
+
+"backend/infrahub/graphql/schema.py" = [
+ ##################################################################################################
+ # Review and change the below later #
+ ##################################################################################################
+ "ANN201", # Missing return type annotation for public function
]
"backend/tests/**.py" = [
@@ -592,8 +631,6 @@ max-complexity = 33
"ANN003", # Missing type annotation for `**kwargs`
"ANN201", # Missing return type annotation for public function
"ANN202", # Missing return type annotation for private function
- "ANN204", # Missing return type annotation for special method
- "ANN205", # Missing return type annotation for staticmethod
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
]
@@ -609,23 +646,10 @@ max-complexity = 33
"E501", # Line too long
]
-"tasks/**.py" = [
- ##################################################################################################
- # Review and change the below later #
- ##################################################################################################
- "ANN001", # Missing type annotation for function argument
- "ANN201", # Missing return type annotation for public function
- "ANN202", # Missing return type annotation for private function
-]
-
-
"utilities/**.py" = [
##################################################################################################
# Review and change the below later #
##################################################################################################
- "ANN002", # Missing type annotation for `*args`
- "ANN003", # Missing type annotation for `**kwargs`
- "ANN201", # Missing return type annotation for public function
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
]
diff --git a/python_sdk b/python_sdk
index f2a19e0732..ae241a5618 160000
--- a/python_sdk
+++ b/python_sdk
@@ -1 +1 @@
-Subproject commit f2a19e0732d8031a11cfc03b8db9a9ed30c8d3c9
+Subproject commit ae241a5618b83c890b89d579a9c7f3c4a5fe105d
diff --git a/sync/LICENSE.txt b/sync/LICENSE.txt
deleted file mode 100644
index 06154b9e1f..0000000000
--- a/sync/LICENSE.txt
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2024 OpsMill SAS
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
\ No newline at end of file
diff --git a/sync/README.md b/sync/README.md
deleted file mode 100644
index 97eae1f4cd..0000000000
--- a/sync/README.md
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
-
-# Infrahub Sync
-
-[Infrahub](https://github.com/opsmill/infrahub) by [OpsMill](https://opsmill.com) acts as a central hub to manage the data, templates and playbooks that powers your infrastructure. At its heart, Infrahub is built on 3 fundamental pillars:
-
-- **A Flexible Schema**: A model of the infrastructure and the relation between the objects in the model, that's easily extensible.
-- **Version Control**: Natively integrated into the graph database which opens up some new capabilities like branching, diffing, and merging data directly in the database.
-- **Unified Storage**: By combining a graph database and git, Infrahub stores data and code needed to manage the infrastructure.
-
-## Introduction
-
-Infrahub Sync is a versatile Python package that synchronizes data between a source and a destination system. It builds on the robust capabilities of `diffsync` to offer flexible and efficient data synchronization across different platforms, including Netbox, Nautobot, and Infrahub. This package features a Typer-based CLI for ease of use, supporting operations such as listing available sync projects, generating diffs, and executing sync processes.
-
-### Features
-
-- **Multiple Systems Support**: Synchronize data between Netbox, Nautobot, and Infrahub.
-- **Flexible Configuration**: Define synchronization tasks with YAML configuration files.
-- **CLI Interface**: Manage sync tasks directly from the command line.
-- **Custom Sync Logic**: Generate Python code for custom sync adapters and models using provided Jinja templates.
-
-### Requirements
-
-Requirements
-
-- The two latest Infrahub releases
-- Python >=3.9, <3.13
-- Python modules:
- - infrahub-sdk >= 0.9.0
-
-## Documentation
-
-Please refer to the [Infrahub Sync](https://docs.infrahub.app/integrations/sync/) documentation.
-
-## Project Structure
-
-```bash
-.
-├── README.md
-├── examples
-│ ├── nautobot-v1_to_infrahub
-│ │ ├── config.yml
-│ │ ├── infrahub
-│ │ │ ├── __init__.py
-│ │ │ ├── sync_adapter.py
-│ │ │ └── sync_models.py
-│ │ └── nautobot
-│ │ ├── __init__.py
-│ │ ├── sync_adapter.py
-│ │ └── sync_models.py
-│ ├── nautobot-v2_to_infrahub
-│ │ ├── config.yml
-│ │ ├── infrahub
-│ │ │ ├── __init__.py
-│ │ │ ├── sync_adapter.py
-│ │ │ └── sync_models.py
-│ │ └── nautobot
-│ │ ├── __init__.py
-│ │ ├── sync_adapter.py
-│ │ └── sync_models.py
-│ └── netbox_to_infrahub
-│ ├── config.yml
-│ ├── infrahub
-│ │ ├── __init__.py
-│ │ ├── sync_adapter.py
-│ │ └── sync_models.py
-│ └── netbox
-│ ├── __init__.py
-│ ├── sync_adapter.py
-│ └── sync_models.py
-├── infrahub-sync
-│ ├── infrahub_sync
-│ │ ├── __init__.py
-│ │ ├── adapters
-│ │ │ ├── infrahub.py
-│ │ │ ├── nautobot.py
-│ │ │ └── netbox.py
-│ │ ├── cli.py
-│ │ ├── generator
-│ │ │ ├── __init__.py
-│ │ │ ├── templates
-│ │ │ │ ├── diffsync_adapter.j2
-│ │ │ │ └── diffsync_models.j2
-│ │ │ └── utils.py
-│ │ └── utils.py
-│ └── tests
-│ └── __init__.py
-├── poetry.lock
-├── potenda
-│ └── potenda
-│ └── __init__.py
-└── pyproject.toml
-```
diff --git a/sync/examples/infrahub_to_peering-manager/config.yml b/sync/examples/infrahub_to_peering-manager/config.yml
deleted file mode 100644
index 77437c7f24..0000000000
--- a/sync/examples/infrahub_to_peering-manager/config.yml
+++ /dev/null
@@ -1,149 +0,0 @@
----
-name: to-peering-manager
-source:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-destination:
- name: peeringmanager
- settings:
- url: "https://demo.peering-manager.net"
- # api_endpoint: "api"
- # auth_method: "token"
- token: "13bf6338aed52d172e33750d39717fff5a5f5d18"
-
-order: [
- "InfraAutonomousSystem",
- "InfraBGPCommunity",
- "InfraBGPRoutingPolicy",
- "InfraBGPPeerGroup",
- "InfraIXP",
- "InfraIXPConnection",
-]
-
-schema_mapping:
- - name: InfraAutonomousSystem
- mapping: peering/autonomous-systems
- identifiers: ["asn"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: comments
- - name: asn
- mapping: asn
- - name: irr_as_set
- mapping: irr_as_set
- - name: ipv4_max_prefixes
- mapping: ipv4_max_prefixes
- - name: ipv6_max_prefixes
- mapping: ipv6_max_prefixes
- - name: affiliated
- mapping: affiliated
-
- - name: InfraBGPCommunity
- mapping: peering/communities
- identifiers: ["name"]
- fields:
- - name: name
- mapping: slug
- - name: label
- mapping: name
- - name: description
- mapping: description
- - name: value
- mapping: value
- - name: community_type
- mapping: type
-
-
- - name: InfraBGPRoutingPolicy
- mapping: peering/routing-policies
- identifiers: ["name"]
- fields:
- - name: name
- mapping: slug
- - name: label
- mapping: name
- - name: description
- mapping: description
- - name: policy_type
- mapping: type
- - name: weight
- mapping: weight
- - name: address_family
- mapping: address_family
- - name: bgp_communities
- mapping: communities
- reference: InfraBGPCommunity
-
- - name: InfraBGPPeerGroup
- mapping: peering/bgp-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: status
- mapping: status.value
- - name: import_policies
- mapping: import_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: export_policies
- mapping: export_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: bgp_communities
- mapping: communities
- reference: InfraBGPCommunity
-
- - name: InfraIXP
- mapping: peering/internet-exchanges
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: status
- mapping: status.value
- - name: import_policies
- mapping: import_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: export_policies
- mapping: export_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: bgp_communities
- mapping: communities
- reference: InfraBGPCommunity
- # Showcase Filters
- filters:
- - field: name
- operation: contains
- value: "S.H.I.E.L.D"
-
- - name: InfraIXPConnection
- mapping: net/connections
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: peeringdb_netixlan
- mapping: peeringdb_netixlan.id
- - name: description
- mapping: description
- - name: status
- mapping: status.value
- - name: vlan
- mapping: vlan
- - name: internet_exchange_point
- mapping: internet_exchange_point
- reference: InfraIXP
- # Showcase Filters
- # As we filter InfraIXP on the name S.H.I.E.L.D, we need to have the same filter here
- # to avoid importing IXP Connection without IXP
- filters:
- - field: internet_exchange_point
- operation: contains
- value: "S.H.I.E.L.D"
diff --git a/sync/examples/infrahub_to_peering-manager/infrahub/sync_adapter.py b/sync/examples/infrahub_to_peering-manager/infrahub/sync_adapter.py
deleted file mode 100644
index 0529f5dfd0..0000000000
--- a/sync/examples/infrahub_to_peering-manager/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- InfraAutonomousSystem,
- InfraBGPCommunity,
- InfraBGPPeerGroup,
- InfraBGPRoutingPolicy,
- InfraIXP,
- InfraIXPConnection,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraBGPPeerGroup = InfraBGPPeerGroup
- InfraBGPRoutingPolicy = InfraBGPRoutingPolicy
- InfraBGPCommunity = InfraBGPCommunity
- InfraIXP = InfraIXP
- InfraIXPConnection = InfraIXPConnection
diff --git a/sync/examples/infrahub_to_peering-manager/infrahub/sync_models.py b/sync/examples/infrahub_to_peering-manager/infrahub/sync_models.py
deleted file mode 100644
index dbbc56fa12..0000000000
--- a/sync/examples/infrahub_to_peering-manager/infrahub/sync_models.py
+++ /dev/null
@@ -1,99 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfraAutonomousSystem(InfrahubModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("asn",)
- _attributes = ("name", "description", "irr_as_set", "ipv4_max_prefixes", "ipv6_max_prefixes", "affiliated")
- name: str
- asn: int
- description: Optional[str] = None
- irr_as_set: Optional[str] = None
- ipv4_max_prefixes: Optional[int] = None
- ipv6_max_prefixes: Optional[int] = None
- affiliated: Optional[bool] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPPeerGroup(InfrahubModel):
- _modelname = "InfraBGPPeerGroup"
- _identifiers = ("name",)
- _attributes = ("import_policies", "export_policies", "bgp_communities", "description", "status")
- name: str
- description: Optional[str] = None
- status: Optional[str] = None
- import_policies: Optional[List[str]] = []
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPRoutingPolicy(InfrahubModel):
- _modelname = "InfraBGPRoutingPolicy"
- _identifiers = ("name",)
- _attributes = ("bgp_communities", "address_family", "label", "description", "policy_type", "weight")
- address_family: int
- label: Optional[str] = None
- description: Optional[str] = None
- name: str
- policy_type: str
- weight: Optional[int] = 1000
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPCommunity(InfrahubModel):
- _modelname = "InfraBGPCommunity"
- _identifiers = ("name",)
- _attributes = ("description", "value", "label", "community_type")
- description: Optional[str] = None
- name: str
- value: str
- label: Optional[str] = None
- community_type: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXP(InfrahubModel):
- _modelname = "InfraIXP"
- _identifiers = ("name",)
- _attributes = ("export_policies", "bgp_communities", "import_policies", "description", "status")
- description: Optional[str] = None
- name: str
- status: Optional[str] = "enabled"
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
- import_policies: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXPConnection(InfrahubModel):
- _modelname = "InfraIXPConnection"
- _identifiers = ("name",)
- _attributes = ("internet_exchange_point", "status", "vlan", "description", "peeringdb_netixlan")
- status: Optional[str] = "enabled"
- vlan: Optional[int] = None
- name: str
- description: Optional[str] = None
- peeringdb_netixlan: Optional[int] = None
- internet_exchange_point: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/infrahub_to_peering-manager/peeringmanager/sync_adapter.py b/sync/examples/infrahub_to_peering-manager/peeringmanager/sync_adapter.py
deleted file mode 100644
index 9c2b88184a..0000000000
--- a/sync/examples/infrahub_to_peering-manager/peeringmanager/sync_adapter.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from infrahub_sync.adapters.peeringmanager import PeeringmanagerAdapter
-
-from .sync_models import (
- InfraAutonomousSystem,
- InfraBGPCommunity,
- InfraBGPPeerGroup,
- InfraBGPRoutingPolicy,
- InfraIXP,
- InfraIXPConnection,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class PeeringmanagerSync(PeeringmanagerAdapter):
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraBGPPeerGroup = InfraBGPPeerGroup
- InfraBGPRoutingPolicy = InfraBGPRoutingPolicy
- InfraBGPCommunity = InfraBGPCommunity
- InfraIXP = InfraIXP
- InfraIXPConnection = InfraIXPConnection
diff --git a/sync/examples/infrahub_to_peering-manager/peeringmanager/sync_models.py b/sync/examples/infrahub_to_peering-manager/peeringmanager/sync_models.py
deleted file mode 100644
index 3ad4dd15c2..0000000000
--- a/sync/examples/infrahub_to_peering-manager/peeringmanager/sync_models.py
+++ /dev/null
@@ -1,99 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.peeringmanager import PeeringmanagerModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfraAutonomousSystem(PeeringmanagerModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("asn",)
- _attributes = ("name", "description", "irr_as_set", "ipv4_max_prefixes", "ipv6_max_prefixes", "affiliated")
- name: str
- asn: int
- description: Optional[str] = None
- irr_as_set: Optional[str] = None
- ipv4_max_prefixes: Optional[int] = None
- ipv6_max_prefixes: Optional[int] = None
- affiliated: Optional[bool] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPPeerGroup(PeeringmanagerModel):
- _modelname = "InfraBGPPeerGroup"
- _identifiers = ("name",)
- _attributes = ("import_policies", "export_policies", "bgp_communities", "description", "status")
- name: str
- description: Optional[str] = None
- status: Optional[str] = None
- import_policies: Optional[List[str]] = []
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPRoutingPolicy(PeeringmanagerModel):
- _modelname = "InfraBGPRoutingPolicy"
- _identifiers = ("name",)
- _attributes = ("bgp_communities", "address_family", "label", "description", "policy_type", "weight")
- address_family: int
- label: Optional[str] = None
- description: Optional[str] = None
- name: str
- policy_type: str
- weight: Optional[int] = 1000
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPCommunity(PeeringmanagerModel):
- _modelname = "InfraBGPCommunity"
- _identifiers = ("name",)
- _attributes = ("description", "value", "label", "community_type")
- description: Optional[str] = None
- name: str
- value: str
- label: Optional[str] = None
- community_type: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXP(PeeringmanagerModel):
- _modelname = "InfraIXP"
- _identifiers = ("name",)
- _attributes = ("export_policies", "bgp_communities", "import_policies", "description", "status")
- description: Optional[str] = None
- name: str
- status: Optional[str] = "enabled"
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
- import_policies: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXPConnection(PeeringmanagerModel):
- _modelname = "InfraIXPConnection"
- _identifiers = ("name",)
- _attributes = ("internet_exchange_point", "status", "vlan", "description", "peeringdb_netixlan")
- status: Optional[str] = "enabled"
- vlan: Optional[int] = None
- name: str
- description: Optional[str] = None
- peeringdb_netixlan: Optional[int] = None
- internet_exchange_point: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/ipfabric_to_infrahub/config.yml b/sync/examples/ipfabric_to_infrahub/config.yml
deleted file mode 100644
index b5a4bc233f..0000000000
--- a/sync/examples/ipfabric_to_infrahub/config.yml
+++ /dev/null
@@ -1,207 +0,0 @@
----
-name: from-ipfabric
-source:
- name: ipfabricsync
- settings:
- base_url: "https://"
- auth: ""
-
-destination:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-order: [
- "LocationGeneric",
- "OrganizationGeneric",
- "InfraPlatform",
- "TemplateDeviceType",
- "InfraNOSVersion",
- "InfraDevice",
- "InfraPartNumber",
- "InfraVLAN",
- "InfraVRF",
- "InfraInterfaceL3",
- # "InfraPrefix",
- # "InfraIPAddress",
-]
-
-schema_mapping:
- - name: LocationGeneric
- mapping: tables/inventory/sites
- fields:
- - name: name
- mapping: siteName
- - name: description
- mapping: name
- - name: type
- static: "Site"
-
- # Device (manufacturer, device types, devices, interfaces)
- - name: OrganizationGeneric
- mapping: tables/inventory/summary/vendors
- fields:
- - name: name
- mapping: vendor
- - name: type
- static: "Vendor"
-
- - name: InfraPlatform
- mapping: tables/inventory/summary/platforms
- fields:
- - name: name
- mapping: platform
- - name: description
- static: "Platform"
-
- - name: TemplateDeviceType
- mapping: tables/inventory/summary/models
- identifiers: ["name", "manufacturer"]
- fields:
- - name: name
- mapping: model
- - name: description
- static: "Device Template"
- - name: manufacturer
- mapping: vendor
- reference: OrganizationGeneric
-
- - name: InfraNOSVersion
- identifiers: ["manufacturer", "model", "version"]
- mapping: tables/management/osver-consistency
- fields:
- - name: version
- mapping: version
- - name: manufacturer
- mapping: vendor
- reference: OrganizationGeneric
- - name: platform
- mapping: platform
- reference: InfraPlatform
- - name: model
- mapping: model
- reference: TemplateDeviceType
-
- - name: InfraDevice
- identifiers: ["location", "hostname"]
- mapping: tables/inventory/devices
- fields:
- - name: hostname
- mapping: hostname
- - name: serial_number
- mapping: sn
- - name: hardware_serial_number
- mapping: snHw
- - name: fqdn
- mapping: fqdn
- - name: model
- mapping: model
- reference: TemplateDeviceType
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: location
- mapping: siteName
- reference: LocationGeneric
- - name: platform
- mapping: platform
- reference: InfraPlatform
- - name: version
- mapping: version
- reference: InfraNOSVersion
-
- - name: InfraPartNumber
- identifiers: ["device", "name"]
- mapping: tables/inventory/pn
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: dscr
- - name: part_id
- mapping: pid
- - name: part_sn
- mapping: sn
- - name: part_vid
- mapping: vid
- - name: manufacturer
- mapping: vendor
- reference: OrganizationGeneric
- - name: model
- mapping: model
- reference: TemplateDeviceType
- - name: device
- mapping: hostname
- reference: InfraDevice
-
- - name: InfraVLAN
- identifiers: ["location", "vlan_id"]
- mapping: tables/vlan/site-summary
- fields:
- - name: name
- mapping: vlanName
- - name: description
- mapping: dscr
- - name: vlan_id
- mapping: vlanId
- - name: location
- mapping: siteName
- reference: LocationGeneric
-
- - name: InfraVRF
- identifiers: ["name"]
- mapping: tables/vrf/detail
- fields:
- - name: name
- mapping: vrf
- - name: vrf_rd
- mapping: rd
-
- - name: InfraInterfaceL3
- identifiers: ["device", "name"]
- mapping: tables/inventory/interfaces
- fields:
- - name: device
- mapping: hostname
- reference: InfraDevice
- - name: name
- mapping: nameOriginal
- - name: description
- mapping: dscr
- - name: speed
- mapping: speedValue
- - name: mtu
- mapping: mtu
- - name: mac_address
- mapping: mac
-
- # - name: InfraPrefix
- # identifiers: ["vrf", "prefix"]
- # mapping: tables/networks
- # fields:
- # - name: prefix
- # mapping: net
- # - name: vrf
- # mapping: vrf
- # reference: InfraVRF
- # - name: vlan
- # mapping: vlanId
- # reference: InfraVLAN
- # - name: location
- # mapping: siteName
- # reference: LocationGeneric
-
- # - name: InfraIPAddress
- # identifiers: ["address"]
- # mapping: tables/addressing/managed-devs
- # fields:
- # - name: address
- # mapping: net
- # - name: description
- # mapping: dscr
- # - name: prefix
- # mapping: net
- # reference: InfraPrefix
- # - name: interface
- # mapping: intName
- # reference: InfraInterfaceL3
diff --git a/sync/examples/ipfabric_to_infrahub/infrahub/sync_adapter.py b/sync/examples/ipfabric_to_infrahub/infrahub/sync_adapter.py
deleted file mode 100644
index 6f32535c6f..0000000000
--- a/sync/examples/ipfabric_to_infrahub/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- InfraDevice,
- InfraInterfaceL3,
- InfraNOSVersion,
- InfraPartNumber,
- InfraPlatform,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- OrganizationGeneric,
- TemplateDeviceType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- InfraDevice = InfraDevice
- InfraInterfaceL3 = InfraInterfaceL3
- InfraNOSVersion = InfraNOSVersion
- InfraPartNumber = InfraPartNumber
- InfraPlatform = InfraPlatform
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- OrganizationGeneric = OrganizationGeneric
- TemplateDeviceType = TemplateDeviceType
diff --git a/sync/examples/ipfabric_to_infrahub/infrahub/sync_models.py b/sync/examples/ipfabric_to_infrahub/infrahub/sync_models.py
deleted file mode 100644
index c809cc5790..0000000000
--- a/sync/examples/ipfabric_to_infrahub/infrahub/sync_models.py
+++ /dev/null
@@ -1,131 +0,0 @@
-from typing import Any, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-
-
-class InfraDevice(InfrahubModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "hostname")
- _attributes = ("platform", "model", "version", "serial_number", "hardware_serial_number", "fqdn")
- hostname: str
- serial_number: str
- hardware_serial_number: str
- fqdn: Optional[str] = None
- location: str
- platform: Optional[str] = None
- model: Optional[str] = None
- version: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL3(InfrahubModel):
- _modelname = "InfraInterfaceL3"
- _identifiers = ("device", "name")
- _attributes = ("description", "speed", "mtu", "mac_address")
- name: str
- description: Optional[str] = None
- speed: Optional[int] = None
- mtu: Optional[int] = 1500
- mac_address: Optional[str] = None
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraNOSVersion(InfrahubModel):
- _modelname = "InfraNOSVersion"
- _identifiers = ("manufacturer", "model", "version")
- _attributes = ("platform",)
- version: str
- manufacturer: str
- platform: Optional[str] = None
- model: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPartNumber(InfrahubModel):
- _modelname = "InfraPartNumber"
- _identifiers = ("device", "name")
- _attributes = ("manufacturer", "model", "description", "part_id", "part_sn", "part_vid")
- name: str
- description: Optional[str] = None
- part_id: Optional[str] = None
- part_sn: Optional[str] = None
- part_vid: Optional[str] = None
- manufacturer: Optional[str] = None
- model: Optional[str] = None
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPlatform(InfrahubModel):
- _modelname = "InfraPlatform"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(InfrahubModel):
- _modelname = "InfraVLAN"
- _identifiers = ("location", "vlan_id")
- _attributes = ("name", "description")
- name: Optional[str] = None
- description: Optional[str] = None
- vlan_id: int
- location: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(InfrahubModel):
- _modelname = "InfraVRF"
- _identifiers = ("name",)
- _attributes = ("vrf_rd",)
- name: str
- vrf_rd: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(InfrahubModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("description", "type")
- name: str
- description: Optional[str] = None
- type: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class OrganizationGeneric(InfrahubModel):
- _modelname = "OrganizationGeneric"
- _identifiers = ("name",)
- _attributes = ("type",)
- name: str
- type: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(InfrahubModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- manufacturer: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/ipfabric_to_infrahub/ipfabricsync/sync_adapter.py b/sync/examples/ipfabric_to_infrahub/ipfabricsync/sync_adapter.py
deleted file mode 100644
index 94ce6b4e20..0000000000
--- a/sync/examples/ipfabric_to_infrahub/ipfabricsync/sync_adapter.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from infrahub_sync.adapters.ipfabricsync import IpfabricsyncAdapter
-
-from .sync_models import (
- InfraDevice,
- InfraInterfaceL3,
- InfraNOSVersion,
- InfraPartNumber,
- InfraPlatform,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- OrganizationGeneric,
- TemplateDeviceType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class IpfabricsyncSync(IpfabricsyncAdapter):
- InfraDevice = InfraDevice
- InfraInterfaceL3 = InfraInterfaceL3
- InfraNOSVersion = InfraNOSVersion
- InfraPartNumber = InfraPartNumber
- InfraPlatform = InfraPlatform
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- OrganizationGeneric = OrganizationGeneric
- TemplateDeviceType = TemplateDeviceType
diff --git a/sync/examples/ipfabric_to_infrahub/ipfabricsync/sync_models.py b/sync/examples/ipfabric_to_infrahub/ipfabricsync/sync_models.py
deleted file mode 100644
index df726188ec..0000000000
--- a/sync/examples/ipfabric_to_infrahub/ipfabricsync/sync_models.py
+++ /dev/null
@@ -1,131 +0,0 @@
-from typing import Any, Optional
-
-from infrahub_sync.adapters.ipfabricsync import IpfabricsyncModel
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-
-
-class InfraDevice(IpfabricsyncModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "hostname")
- _attributes = ("platform", "model", "version", "serial_number", "hardware_serial_number", "fqdn")
- hostname: str
- serial_number: str
- hardware_serial_number: str
- fqdn: Optional[str] = None
- location: str
- platform: Optional[str] = None
- model: Optional[str] = None
- version: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL3(IpfabricsyncModel):
- _modelname = "InfraInterfaceL3"
- _identifiers = ("device", "name")
- _attributes = ("description", "speed", "mtu", "mac_address")
- name: str
- description: Optional[str] = None
- speed: Optional[int] = None
- mtu: Optional[int] = 1500
- mac_address: Optional[str] = None
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraNOSVersion(IpfabricsyncModel):
- _modelname = "InfraNOSVersion"
- _identifiers = ("manufacturer", "model", "version")
- _attributes = ("platform",)
- version: str
- manufacturer: str
- platform: Optional[str] = None
- model: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPartNumber(IpfabricsyncModel):
- _modelname = "InfraPartNumber"
- _identifiers = ("device", "name")
- _attributes = ("manufacturer", "model", "description", "part_id", "part_sn", "part_vid")
- name: str
- description: Optional[str] = None
- part_id: Optional[str] = None
- part_sn: Optional[str] = None
- part_vid: Optional[str] = None
- manufacturer: Optional[str] = None
- model: Optional[str] = None
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPlatform(IpfabricsyncModel):
- _modelname = "InfraPlatform"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(IpfabricsyncModel):
- _modelname = "InfraVLAN"
- _identifiers = ("location", "vlan_id")
- _attributes = ("name", "description")
- name: Optional[str] = None
- description: Optional[str] = None
- vlan_id: int
- location: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(IpfabricsyncModel):
- _modelname = "InfraVRF"
- _identifiers = ("name",)
- _attributes = ("vrf_rd",)
- name: str
- vrf_rd: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(IpfabricsyncModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("description", "type")
- name: str
- description: Optional[str] = None
- type: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class OrganizationGeneric(IpfabricsyncModel):
- _modelname = "OrganizationGeneric"
- _identifiers = ("name",)
- _attributes = ("type",)
- name: str
- type: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(IpfabricsyncModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- manufacturer: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/librenms_to_infrahub/config.yml b/sync/examples/librenms_to_infrahub/config.yml
deleted file mode 100644
index e794aeac29..0000000000
--- a/sync/examples/librenms_to_infrahub/config.yml
+++ /dev/null
@@ -1,68 +0,0 @@
----
-name: from-librenms
-
-source:
- name: librenms
- settings:
- url: "http://localhost:8080"
- # api_endpoint: "api/v0"
- # auth_method: "x-auth-token"
- # token: "LIBRENMS_TOKEN"
-
-destination:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-order: [
- "CoreStandardGroup",
- "LocationSite",
- "IpamIPAddress",
- "InfraDevice",
-]
-
-schema_mapping:
- - name: CoreStandardGroup
- mapping: devicegroups
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: desc
-
- - name: LocationSite
- mapping: resources/locations
- identifiers: ["name"]
- fields:
- - name: name
- mapping: location
- - name: description
- mapping: location
-
- # Primary Device IP
- - name: IpamIPAddress
- mapping: devices
- identifiers: ["address"]
- fields:
- - name: address
- mapping: ip
- - name: description
- mapping: hostname
-
- - name: InfraDevice
- mapping: devices
- identifiers: ["name"]
- filters:
- - field: hostname
- operation: contains
- value: "xxx"
- fields:
- - name: name
- mapping: hostname
- - name: serial_number
- mapping: serial
- - name: type
- mapping: hardware
- - name: site
- mapping: location
- reference: LocationSite
diff --git a/sync/examples/librenms_to_infrahub/infrahub/sync_adapter.py b/sync/examples/librenms_to_infrahub/infrahub/sync_adapter.py
deleted file mode 100644
index fa13a3a8d7..0000000000
--- a/sync/examples/librenms_to_infrahub/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- CoreStandardGroup,
- InfraDevice,
- IpamIPAddress,
- LocationSite,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- CoreStandardGroup = CoreStandardGroup
- InfraDevice = InfraDevice
- IpamIPAddress = IpamIPAddress
- LocationSite = LocationSite
diff --git a/sync/examples/librenms_to_infrahub/infrahub/sync_models.py b/sync/examples/librenms_to_infrahub/infrahub/sync_models.py
deleted file mode 100644
index 82d5ebd25d..0000000000
--- a/sync/examples/librenms_to_infrahub/infrahub/sync_models.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from typing import Any, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(InfrahubModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(InfrahubModel):
- _modelname = "InfraDevice"
- _identifiers = ("name",)
- _attributes = ("site", "type", "serial_number")
- name: str
- type: str
- serial_number: str
- site: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class IpamIPAddress(InfrahubModel):
- _modelname = "IpamIPAddress"
- _identifiers = ("address",)
- _attributes = ("description",)
- address: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationSite(InfrahubModel):
- _modelname = "LocationSite"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/librenms_to_infrahub/librenms/sync_adapter.py b/sync/examples/librenms_to_infrahub/librenms/sync_adapter.py
deleted file mode 100644
index bfe97c6af3..0000000000
--- a/sync/examples/librenms_to_infrahub/librenms/sync_adapter.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from infrahub_sync.adapters.librenms import LibrenmsAdapter
-
-from .sync_models import (
- CoreStandardGroup,
- InfraDevice,
- IpamIPAddress,
- LocationSite,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class LibrenmsSync(LibrenmsAdapter):
- CoreStandardGroup = CoreStandardGroup
- InfraDevice = InfraDevice
- IpamIPAddress = IpamIPAddress
- LocationSite = LocationSite
diff --git a/sync/examples/librenms_to_infrahub/librenms/sync_models.py b/sync/examples/librenms_to_infrahub/librenms/sync_models.py
deleted file mode 100644
index 96e3cb2b2a..0000000000
--- a/sync/examples/librenms_to_infrahub/librenms/sync_models.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from typing import Any, Optional
-
-from infrahub_sync.adapters.librenms import LibrenmsModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(LibrenmsModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(LibrenmsModel):
- _modelname = "InfraDevice"
- _identifiers = ("name",)
- _attributes = ("site", "type", "serial_number")
- name: str
- type: str
- serial_number: str
- site: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class IpamIPAddress(LibrenmsModel):
- _modelname = "IpamIPAddress"
- _identifiers = ("address",)
- _attributes = ("description",)
- address: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationSite(LibrenmsModel):
- _modelname = "LocationSite"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/nautobot-v1_to_infrahub/config.yml b/sync/examples/nautobot-v1_to_infrahub/config.yml
deleted file mode 100644
index 3c0f8d95a0..0000000000
--- a/sync/examples/nautobot-v1_to_infrahub/config.yml
+++ /dev/null
@@ -1,522 +0,0 @@
----
-name: from-nautobot-v1
-source:
- name: nautobot
- settings:
- url: "http://nautobot:8080"
-
-destination:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-order: [
- "BuiltinTag",
- "RoleGeneric",
- # "StatusGeneric",
- "CoreStandardGroup",
- "TemplateLocationType",
- "OgranizationGeneric",
- "LocationGeneric",
- "InfraRack",
- "TemplateDeviceType",
- "InfraPlatform",
- "InfraProviderNetwork",
- "TemplateCircuitType",
- "InfraCircuit",
- "InfraRouteTarget",
- "InfraVRF",
- "InfraDevice",
- "InfraVLAN",
- "InfraPrefix",
- "InfraIPAddress",
- "InfraRearPort",
- "InfraFrontPort",
- "InfraInterfaceL2L3"
-]
-
-schema_mapping:
- # Tags
- - name: BuiltinTag
- mapping: extras.tags
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
-
- # Roles (Device Role, Rack Role, IPAM Role)
- - name: RoleGeneric
- mapping: dcim.device_roles
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: RoleGeneric
- mapping: dcim.rack_roles
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: RoleGeneric
- mapping: ipam.roles
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
-
- # Status
- - name: StatusGeneric
- mapping: extras.statuses
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: label
- mapping: display
-
- # Tenancy (tenants, tenant groups)
- - name: CoreStandardGroup
- mapping: tenancy.tenant-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: OgranizationGeneric
- mapping: tenancy.tenants
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: type
- static: "Tenant"
- - name: group
- mapping: group
- reference: CoreStandardGroup
-
- # Sites (Region, Sites, Location)
- - name: TemplateLocationType
- mapping: dcim.location-types
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: LocationGeneric
- mapping: dcim.regions
- fields:
- - name: name
- mapping: slug
- - name: description
- mapping: name
- - name: type
- static: "Region"
- - name: LocationGeneric
- mapping: dcim.sites
- fields:
- - name: name
- mapping: slug
- - name: description
- mapping: name
- - name: type
- static: "Site"
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
- - name: LocationGeneric
- mapping: dcim.locations
- fields:
- - name: name
- mapping: slug
- - name: description
- mapping: name
- - name: type
- static: "Location"
- - name: location_type
- mapping: location_type
- reference: TemplateLocationType
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
-
- # Racks
- - name: InfraRack
- mapping: dcim.racks
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: location
- mapping: location
- reference: LocationGeneric
- - name: site
- mapping: site
- reference: LocationGeneric
- - name: height
- mapping: u_height
- - name: serial_number
- mapping: serial
- - name: asset_tag
- mapping: asset_tag
- - name: facility_id
- mapping: facility_id
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # Device (manufacturer, device types, platform, devices)
- - name: OgranizationGeneric
- mapping: dcim.manufacturers
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: type
- static: "Manufacturer"
- - name: InfraPlatform
- mapping: dcim.platforms
- identifiers: ["name", "manufacturer"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: napalm_driver
- mapping: napalm_driver
- - name: manufacturer
- mapping: manufacturer
- reference: OgranizationGeneric
- - name: TemplateDeviceType
- mapping: dcim.device-types
- identifiers: ["name", "manufacturer"]
- fields:
- - name: name
- mapping: model
- - name: part_number
- mapping: part_number
- - name: full_depth
- mapping: is_full_depth
- - name: height
- mapping: u_height
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: manufacturer
- mapping: manufacturer
- reference: OgranizationGeneric
- # -> Device validate_unique()
- # https://github.com/nautobot/nautobot/blob/develop/nautobot/dcim/models/devices.py#L541C9-L541C24
- - name: InfraDevice
- identifiers: ["location", "organization", "name"]
- mapping: dcim.devices
- fields:
- - name: name
- mapping: name
- - name: serial_number
- mapping: serial
- - name: asset_tag
- mapping: asset_tag
- - name: model
- mapping: device_type
- reference: TemplateDeviceType
- - name: platform
- mapping: platform
- reference: InfraPlatform
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
- - name: role
- mapping: device_role
- reference: RoleGeneric
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: location
- mapping: location
- reference: LocationGeneric
- - name: rack
- mapping: rack
- reference: InfraRack
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # Circuits (Provider, Provider Network, Circuits Types, Circuits)
- - name: OgranizationGeneric
- mapping: circuits.providers
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: type
- static: "Provider"
- - name: InfraProviderNetwork
- mapping: circuits.provider-networks
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: vendor_id
- mapping: service_id
- - name: provider
- mapping: provider.slug
- - name: description
- mapping: description
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: provider
- mapping: provider
- reference: OgranizationGeneric
- - name: TemplateCircuitType
- mapping: circuits.circuit-types
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: InfraCircuit
- mapping: circuits.circuits
- identifiers: ["circuit_id"]
- fields:
- - name: circuit_id
- mapping: cid
- - name: vendor_id
- mapping: cid
- - name: provider
- mapping: provider
- reference: OgranizationGeneric
- - name: description
- mapping: description
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: type
- mapping: type
- reference: TemplateCircuitType
- # - name: tenant
- # mapping: tenant
- # reference: OgranizationGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # BGP Plugin (Autonomous System, BGP Session, BGP Peer Group)
- - name: InfraAutonomousSystem
- mapping: plugin.bgp.autonomous-systems
- identifiers: ["name"]
- fields:
- - name: name
- mapping: asn
- - name: asn
- mapping: asn
- - name: description
- mapping: description
- - name: organization
- mapping: provider
- reference: OgranizationGeneric
-
-# IPAM (VRF, VLANs Groups, VLANs, Prefixes, IPs)
- - name: InfraRouteTarget
- mapping: ipam.route-targets
- identifiers: ["name", "organization"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
- - name: InfraVRF
- mapping: ipam.vrfs
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
- - name: vrf_rd
- mapping: rd
- - name: import_rt
- mapping: import_targets
- reference: InfraRouteTarget
- - name: export_rt
- mapping: export_targets
- reference: InfraRouteTarget
- - name: CoreStandardGroup
- mapping: ipam.vlan-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- # - name: location
- # mapping: location
- # reference: LocationGeneric
- - name: InfraVLAN
- mapping: ipam.vlans
- identifiers: ["name", "vlan_id", "location", "organization"]
- fields:
- - name: name
- mapping: name
- - name: vlan_id
- mapping: vid
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
- - name: description
- mapping: description
- - name: location
- mapping: location
- reference: LocationGeneric
- - name: role
- mapping: role
- reference: RoleGeneric
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: vlan_group
- mapping: group
- reference: CoreStandardGroup
- - name: InfraPrefix
- mapping: ipam.prefixes
- identifiers: ["prefix", "vrf", "organization"]
- fields:
- - name: prefix
- mapping: prefix
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
- - name: vrf
- mapping: vrf
- reference: InfraVRF
- - name: role
- mapping: role
- reference: RoleGeneric
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: vlan
- mapping: vlan
- reference: InfraVLAN
- - name: location
- mapping: location
- reference: LocationGeneric
- - name: InfraIPAddress
- mapping: ipam.ip-addresses
- identifiers: ["address", "vrf"]
- fields:
- - name: address
- mapping: address
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OgranizationGeneric
- - name: vrf
- mapping: vrf
- reference: InfraVRF
- - name: role
- mapping: role
- reference: RoleGeneric
- # - name: status
- # mapping: status
- # reference: StatusGeneric
-
- # Interfaces (interfaces, rear port, front port)
- - name: InfraInterfaceL2L3
- identifiers: ["name", "device"]
- mapping: dcim.interfaces
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: interface_type
- mapping: type.label
- - name: l2_mode
- mapping: mode.label
- - name: mac_address
- mapping: mac_address
- - name: mgmt_only
- mapping: mgmt_only
- - name: untagged_vlan
- mapping: untagged_vlan
- reference: InfraVLAN
- - name: tagged_vlan
- mapping: tagged_vlans
- reference: InfraVLAN
- - name: device
- mapping: device
- reference: InfraDevice
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: InfraFrontPort
- identifiers: ["name", "device"]
- mapping: dcim.front-ports
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: port_type
- mapping: type.label
- - name: rear_port
- mapping: rear_port
- reference: InfraRearPort
- - name: device
- mapping: device
- reference: InfraDevice
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: InfraRearPort
- identifiers: ["name", "device"]
- mapping: dcim.rear-ports
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: port_type
- mapping: type.label
- - name: device
- mapping: device
- reference: InfraDevice
- # - name: status
- # mapping: status
- # reference: StatusGeneric
diff --git a/sync/examples/nautobot-v1_to_infrahub/infrahub/sync_adapter.py b/sync/examples/nautobot-v1_to_infrahub/infrahub/sync_adapter.py
deleted file mode 100644
index f3956cc2ec..0000000000
--- a/sync/examples/nautobot-v1_to_infrahub/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- BuiltinTag,
- CoreStandardGroup,
- InfraAutonomousSystem,
- InfraCircuit,
- InfraDevice,
- InfraFrontPort,
- InfraInterfaceL2L3,
- InfraIPAddress,
- InfraPlatform,
- InfraPrefix,
- InfraProviderNetwork,
- InfraRack,
- InfraRearPort,
- InfraRouteTarget,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- RoleGeneric,
- StatusGeneric,
- TemplateCircuitType,
- TemplateDeviceType,
- TemplateLocationType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- CoreStandardGroup = CoreStandardGroup
- BuiltinTag = BuiltinTag
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraCircuit = InfraCircuit
- InfraDevice = InfraDevice
- InfraFrontPort = InfraFrontPort
- InfraIPAddress = InfraIPAddress
- InfraInterfaceL2L3 = InfraInterfaceL2L3
- InfraPlatform = InfraPlatform
- InfraPrefix = InfraPrefix
- InfraProviderNetwork = InfraProviderNetwork
- InfraRack = InfraRack
- InfraRearPort = InfraRearPort
- InfraRouteTarget = InfraRouteTarget
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- RoleGeneric = RoleGeneric
- StatusGeneric = StatusGeneric
- TemplateCircuitType = TemplateCircuitType
- TemplateDeviceType = TemplateDeviceType
- TemplateLocationType = TemplateLocationType
diff --git a/sync/examples/nautobot-v1_to_infrahub/infrahub/sync_models.py b/sync/examples/nautobot-v1_to_infrahub/infrahub/sync_models.py
deleted file mode 100644
index 3e1a312ad0..0000000000
--- a/sync/examples/nautobot-v1_to_infrahub/infrahub/sync_models.py
+++ /dev/null
@@ -1,291 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-
-
-class CoreStandardGroup(InfrahubModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class BuiltinTag(InfrahubModel):
- _modelname = "BuiltinTag"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraAutonomousSystem(InfrahubModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("name",)
- _attributes = ("organization", "description")
- name: str
- asn: int
- description: Optional[str] = None
- organization: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraCircuit(InfrahubModel):
- _modelname = "InfraCircuit"
- _identifiers = ("circuit_id",)
- _attributes = ("provider", "type", "tags", "description", "vendor_id")
- circuit_id: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- type: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(InfrahubModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "organization", "name")
- _attributes = ("model", "rack", "role", "tags", "platform", "serial_number", "asset_tag")
- name: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- model: str
- rack: Optional[str] = None
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- platform: Optional[str] = None
- organization: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraFrontPort(InfrahubModel):
- _modelname = "InfraFrontPort"
- _identifiers = ("name", "device")
- _attributes = ("rear_port", "description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- rear_port: Optional[List[str]] = []
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIPAddress(InfrahubModel):
- _modelname = "InfraIPAddress"
- _identifiers = ("address", "vrf")
- _attributes = ("organization", "role", "description")
- address: str
- description: Optional[str] = None
- organization: Optional[str] = None
- vrf: Optional[str] = None
- role: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL2L3(InfrahubModel):
- _modelname = "InfraInterfaceL2L3"
- _identifiers = ("name", "device")
- _attributes = ("tagged_vlan", "tags", "l2_mode", "description", "mgmt_only", "mac_address", "interface_type")
- l2_mode: Optional[str] = None
- name: str
- description: Optional[str] = None
- mgmt_only: Optional[bool] = False
- mac_address: Optional[str] = None
- interface_type: Optional[str] = None
- untagged_vlan: Optional[str] = None
- tagged_vlan: Optional[List[str]] = []
- device: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPlatform(InfrahubModel):
- _modelname = "InfraPlatform"
- _identifiers = ("name", "manufacturer")
- _attributes = ("description", "napalm_driver")
- name: str
- description: Optional[str] = None
- napalm_driver: Optional[str] = None
- manufacturer: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPrefix(InfrahubModel):
- _modelname = "InfraPrefix"
- _identifiers = ("prefix", "vrf", "organization")
- _attributes = ("role", "vlan", "description")
- prefix: str
- description: Optional[str] = None
- organization: Optional[str] = None
- role: Optional[str] = None
- vrf: Optional[str] = None
- vlan: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraProviderNetwork(InfrahubModel):
- _modelname = "InfraProviderNetwork"
- _identifiers = ("name",)
- _attributes = ("provider", "tags", "description", "vendor_id")
- name: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRack(InfrahubModel):
- _modelname = "InfraRack"
- _identifiers = ("name",)
- _attributes = ("location", "role", "tags", "height", "facility_id", "serial_number", "asset_tag")
- name: str
- height: Optional[int] = None
- facility_id: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRearPort(InfrahubModel):
- _modelname = "InfraRearPort"
- _identifiers = ("name", "device")
- _attributes = ("description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRouteTarget(InfrahubModel):
- _modelname = "InfraRouteTarget"
- _identifiers = ("name", "organization")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- organization: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(InfrahubModel):
- _modelname = "InfraVLAN"
- _identifiers = ("name", "vlan_id", "location", "organization")
- _attributes = ("role", "vlan_group", "description")
- name: str
- description: Optional[str] = None
- vlan_id: int
- organization: Optional[str] = None
- role: Optional[str] = None
- vlan_group: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(InfrahubModel):
- _modelname = "InfraVRF"
- _identifiers = ("name",)
- _attributes = ("organization", "import_rt", "export_rt", "description", "vrf_rd")
- name: str
- description: Optional[str] = None
- vrf_rd: Optional[str] = None
- organization: Optional[str] = None
- import_rt: Optional[List[str]] = []
- export_rt: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(InfrahubModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("organization", "location_type", "description", "type")
- name: str
- description: Optional[str] = None
- type: str
- organization: Optional[str] = None
- location_type: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class RoleGeneric(InfrahubModel):
- _modelname = "RoleGeneric"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class StatusGeneric(InfrahubModel):
- _modelname = "StatusGeneric"
- _identifiers = ("name",)
- _attributes = ("label", "description")
- name: str
- label: Optional[str] = None
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateCircuitType(InfrahubModel):
- _modelname = "TemplateCircuitType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(InfrahubModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("tags", "part_number", "height", "full_depth")
- part_number: Optional[str] = None
- height: Optional[int] = None
- full_depth: Optional[bool] = None
- name: str
- manufacturer: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateLocationType(InfrahubModel):
- _modelname = "TemplateLocationType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/nautobot-v1_to_infrahub/nautobot/sync_adapter.py b/sync/examples/nautobot-v1_to_infrahub/nautobot/sync_adapter.py
deleted file mode 100644
index 0038d2c923..0000000000
--- a/sync/examples/nautobot-v1_to_infrahub/nautobot/sync_adapter.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from infrahub_sync.adapters.nautobot import NautobotAdapter
-
-from .sync_models import (
- BuiltinTag,
- CoreStandardGroup,
- InfraAutonomousSystem,
- InfraCircuit,
- InfraDevice,
- InfraFrontPort,
- InfraInterfaceL2L3,
- InfraIPAddress,
- InfraPlatform,
- InfraPrefix,
- InfraProviderNetwork,
- InfraRack,
- InfraRearPort,
- InfraRouteTarget,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- RoleGeneric,
- StatusGeneric,
- TemplateCircuitType,
- TemplateDeviceType,
- TemplateLocationType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class NautobotSync(NautobotAdapter):
- CoreStandardGroup = CoreStandardGroup
- BuiltinTag = BuiltinTag
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraCircuit = InfraCircuit
- InfraDevice = InfraDevice
- InfraFrontPort = InfraFrontPort
- InfraIPAddress = InfraIPAddress
- InfraInterfaceL2L3 = InfraInterfaceL2L3
- InfraPlatform = InfraPlatform
- InfraPrefix = InfraPrefix
- InfraProviderNetwork = InfraProviderNetwork
- InfraRack = InfraRack
- InfraRearPort = InfraRearPort
- InfraRouteTarget = InfraRouteTarget
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- RoleGeneric = RoleGeneric
- StatusGeneric = StatusGeneric
- TemplateCircuitType = TemplateCircuitType
- TemplateDeviceType = TemplateDeviceType
- TemplateLocationType = TemplateLocationType
diff --git a/sync/examples/nautobot-v1_to_infrahub/nautobot/sync_models.py b/sync/examples/nautobot-v1_to_infrahub/nautobot/sync_models.py
deleted file mode 100644
index e907698f7d..0000000000
--- a/sync/examples/nautobot-v1_to_infrahub/nautobot/sync_models.py
+++ /dev/null
@@ -1,291 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.nautobot import NautobotModel
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-
-
-class CoreStandardGroup(NautobotModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class BuiltinTag(NautobotModel):
- _modelname = "BuiltinTag"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraAutonomousSystem(NautobotModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("name",)
- _attributes = ("organization", "description")
- name: str
- asn: int
- description: Optional[str] = None
- organization: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraCircuit(NautobotModel):
- _modelname = "InfraCircuit"
- _identifiers = ("circuit_id",)
- _attributes = ("provider", "type", "tags", "description", "vendor_id")
- circuit_id: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- type: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(NautobotModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "organization", "name")
- _attributes = ("model", "rack", "role", "tags", "platform", "serial_number", "asset_tag")
- name: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- model: str
- rack: Optional[str] = None
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- platform: Optional[str] = None
- organization: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraFrontPort(NautobotModel):
- _modelname = "InfraFrontPort"
- _identifiers = ("name", "device")
- _attributes = ("rear_port", "description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- rear_port: Optional[List[str]] = []
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIPAddress(NautobotModel):
- _modelname = "InfraIPAddress"
- _identifiers = ("address", "vrf")
- _attributes = ("organization", "role", "description")
- address: str
- description: Optional[str] = None
- organization: Optional[str] = None
- vrf: Optional[str] = None
- role: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL2L3(NautobotModel):
- _modelname = "InfraInterfaceL2L3"
- _identifiers = ("name", "device")
- _attributes = ("tagged_vlan", "tags", "l2_mode", "description", "mgmt_only", "mac_address", "interface_type")
- l2_mode: Optional[str] = None
- name: str
- description: Optional[str] = None
- mgmt_only: Optional[bool] = False
- mac_address: Optional[str] = None
- interface_type: Optional[str] = None
- untagged_vlan: Optional[str] = None
- tagged_vlan: Optional[List[str]] = []
- device: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPlatform(NautobotModel):
- _modelname = "InfraPlatform"
- _identifiers = ("name", "manufacturer")
- _attributes = ("description", "napalm_driver")
- name: str
- description: Optional[str] = None
- napalm_driver: Optional[str] = None
- manufacturer: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPrefix(NautobotModel):
- _modelname = "InfraPrefix"
- _identifiers = ("prefix", "vrf", "organization")
- _attributes = ("role", "vlan", "description")
- prefix: str
- description: Optional[str] = None
- organization: Optional[str] = None
- role: Optional[str] = None
- vrf: Optional[str] = None
- vlan: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraProviderNetwork(NautobotModel):
- _modelname = "InfraProviderNetwork"
- _identifiers = ("name",)
- _attributes = ("provider", "tags", "description", "vendor_id")
- name: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRack(NautobotModel):
- _modelname = "InfraRack"
- _identifiers = ("name",)
- _attributes = ("location", "role", "tags", "height", "facility_id", "serial_number", "asset_tag")
- name: str
- height: Optional[int] = None
- facility_id: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRearPort(NautobotModel):
- _modelname = "InfraRearPort"
- _identifiers = ("name", "device")
- _attributes = ("description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- device: str
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRouteTarget(NautobotModel):
- _modelname = "InfraRouteTarget"
- _identifiers = ("name", "organization")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- organization: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(NautobotModel):
- _modelname = "InfraVLAN"
- _identifiers = ("name", "vlan_id", "location", "organization")
- _attributes = ("role", "vlan_group", "description")
- name: str
- description: Optional[str] = None
- vlan_id: int
- organization: Optional[str] = None
- role: Optional[str] = None
- vlan_group: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(NautobotModel):
- _modelname = "InfraVRF"
- _identifiers = ("name",)
- _attributes = ("organization", "import_rt", "export_rt", "description", "vrf_rd")
- name: str
- description: Optional[str] = None
- vrf_rd: Optional[str] = None
- organization: Optional[str] = None
- import_rt: Optional[List[str]] = []
- export_rt: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(NautobotModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("organization", "location_type", "description", "type")
- name: str
- description: Optional[str] = None
- type: str
- organization: Optional[str] = None
- location_type: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class RoleGeneric(NautobotModel):
- _modelname = "RoleGeneric"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class StatusGeneric(NautobotModel):
- _modelname = "StatusGeneric"
- _identifiers = ("name",)
- _attributes = ("label", "description")
- name: str
- label: Optional[str] = None
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateCircuitType(NautobotModel):
- _modelname = "TemplateCircuitType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(NautobotModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("tags", "part_number", "height", "full_depth")
- part_number: Optional[str] = None
- height: Optional[int] = None
- full_depth: Optional[bool] = None
- name: str
- manufacturer: str
- tags: Optional[List[str]] = []
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateLocationType(NautobotModel):
- _modelname = "TemplateLocationType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/nautobot-v2_to_infrahub/config.yml b/sync/examples/nautobot-v2_to_infrahub/config.yml
deleted file mode 100644
index 529211e5ff..0000000000
--- a/sync/examples/nautobot-v2_to_infrahub/config.yml
+++ /dev/null
@@ -1,527 +0,0 @@
----
-name: from-nautobot-v2
-source:
- name: nautobot
- settings:
- url: "https://demo.nautobot.com"
- token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-
-destination:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-# store:
-# type: redis
-# settings:
-# host: localhost
-# port: 6379
-
-order: [
- "BuiltinTag",
- "RoleGeneric",
- "StatusGeneric",
- "CoreStandardGroup",
- "OrganizationGeneric",
- "TemplateLocationType",
- "LocationGeneric",
- "InfraRack",
- "TemplateDeviceType",
- "InfraPlatform",
- "InfraProviderNetwork",
- "TemplateCircuitType",
- "InfraCircuit",
- "NautobotNamespace",
- "InfraRouteTarget",
- "InfraVLAN",
- "InfraVRF",
- # "InfraDevice",
- "InfraPrefix",
- # "InfraInterfaceL2L3",
- "InfraRearPort",
- "InfraFrontPort",
- # "InfraIPAddress",
-]
-
-schema_mapping:
- # Tags
- - name: BuiltinTag
- mapping: extras.tags
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
-
- # Roles (Device Role, Rack Role, IPAM Role, and IPAddressRoleChoices)
- - name: RoleGeneric
- mapping: extras.roles
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: label
- mapping: display
-
- # Status (Device Role, Rack Role, IPAM Role, and IPAddressRoleChoices)
- - name: StatusGeneric
- mapping: extras.statuses
- identifiers: ["name"]
- fields:
- - name: name
- mapping: new_name
- - name: description
- mapping: description
- - name: label
- mapping: new_label
- # Transform the "fake" Null Status from Nautobot v2
- transforms:
- - field: new_name
- expression: "{{ 'default' if name == 'NULL' else name }}"
- - field: new_label
- expression: "{{ 'Default' if display == 'NULL' else display }}"
-
- # Tenancy (tenants, tenant groups)
- - name: CoreStandardGroup
- mapping: tenancy.tenant-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: OrganizationGeneric
- mapping: tenancy.tenants
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: type
- static: "Tenant"
- - name: group
- mapping: tenant_group
- reference: CoreStandardGroup
-
- # Locations (Location Type, Locations)
- - name: TemplateLocationType
- mapping: dcim.location-types
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: LocationGeneric
- mapping: dcim.locations
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: location_type
- mapping: location_type
- reference: TemplateLocationType
- - name: status
- mapping: status
- reference: StatusGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # Racks
- - name: InfraRack
- mapping: dcim.racks
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: location
- mapping: location
- reference: LocationGeneric
- - name: height
- mapping: u_height
- - name: serial_number
- mapping: serial
- - name: asset_tag
- mapping: asset_tag
- - name: facility_id
- mapping: facility_id
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # Device (manufacturer, device types, platform, devices)
- - name: OrganizationGeneric
- mapping: dcim.manufacturers
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: type
- static: "Manufacturer"
- - name: InfraPlatform
- mapping: dcim.platforms
- identifiers: ["name", "manufacturer"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: napalm_driver
- mapping: napalm_driver
- - name: manufacturer
- mapping: manufacturer
- reference: OrganizationGeneric
- - name: TemplateDeviceType
- mapping: dcim.device-types
- identifiers: ["name", "manufacturer"]
- fields:
- - name: name
- mapping: model
- - name: part_number
- mapping: part_number
- - name: full_depth
- mapping: is_full_depth
- - name: height
- mapping: u_height
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: manufacturer
- mapping: manufacturer
- reference: OrganizationGeneric
- # -> Device validate_unique()
- # https://github.com/nautobot/nautobot/blob/develop/nautobot/dcim/models/devices.py#L541C9-L541C24
- - name: InfraDevice
- identifiers: ["location", "organization", "name"]
- mapping: dcim.devices
- fields:
- - name: name
- mapping: name
- - name: serial_number
- mapping: serial
- - name: asset_tag
- mapping: asset_tag
- - name: model
- mapping: device_type
- reference: TemplateDeviceType
- - name: platform
- mapping: platform
- reference: InfraPlatform
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: status
- mapping: status
- reference: StatusGeneric
- - name: location
- mapping: location
- reference: LocationGeneric
- - name: rack
- mapping: rack
- reference: InfraRack
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # Circuits (Provider, Provider Network, Circuits Types, Circuits)
- - name: OrganizationGeneric
- mapping: circuits.providers
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: type
- static: "Provider"
- - name: InfraProviderNetwork
- mapping: circuits.provider-networks
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: vendor_id
- mapping: service_id
- - name: provider
- mapping: provider.slug
- - name: description
- mapping: description
- - name: status
- mapping: status
- reference: StatusGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: provider
- mapping: provider
- reference: OrganizationGeneric
- - name: TemplateCircuitType
- mapping: circuits.circuit-types
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: InfraCircuit
- mapping: circuits.circuits
- identifiers: ["circuit_id"]
- # Showcase of the filters on the Circuits, it will import the ones starting with a CID starting with ntt
- filters:
- - field: cid
- operation: "contains"
- value: "ntt"
- transforms:
- - field: circuit_id
- expression: "{{ cid.upper() }}"
- fields:
- - name: circuit_id
- mapping: cid
- - name: vendor_id
- mapping: cid
- - name: provider
- mapping: provider
- reference: OrganizationGeneric
- - name: description
- mapping: description
- - name: status
- mapping: status
- reference: StatusGeneric
- - name: type
- mapping: circuit_type
- reference: TemplateCircuitType
- # - name: tenant
- # mapping: tenant
- # reference: OrganizationGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # BGP Plugin (Autonomous System, BGP Session, BGP Peer Group)
- - name: InfraAutonomousSystem
- mapping: plugin.bgp.autonomous-systems
- identifiers: ["name"]
- fields:
- - name: name
- mapping: asn
- - name: asn
- mapping: asn
- - name: description
- mapping: description
- - name: organization
- mapping: provider
- reference: OrganizationGeneric
-
-# IPAM (Namepsace, VRF, VLANs Groups, VLANs, Prefixes, IPs)
- - name: NautobotNamespace
- mapping: ipam.namespaces
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: InfraRouteTarget
- mapping: ipam.route-targets
- identifiers: ["name", "organization"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: InfraVRF
- mapping: ipam.vrfs
- identifiers: ["name", "ip_namespace"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: ip_namespace
- mapping: namespace
- reference: NautobotNamespace
- - name: vrf_rd
- mapping: rd
- - name: import_rt
- mapping: import_targets
- reference: InfraRouteTarget
- - name: export_rt
- mapping: export_targets
- reference: InfraRouteTarget
- - name: CoreStandardGroup
- mapping: ipam.vlan-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- # - name: location
- # mapping: location
- # reference: LocationGeneric
- - name: InfraVLAN
- mapping: ipam.vlans
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: vlan_id
- mapping: vid
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: description
- mapping: description
- - name: locations
- mapping: locations
- reference: LocationGeneric
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: status
- mapping: status
- reference: StatusGeneric
- - name: vlan_group
- mapping: vlan_group
- reference: CoreStandardGroup
- - name: InfraPrefix
- mapping: ipam.prefixes
- identifiers: ["prefix", "ip_namespace"]
- fields:
- - name: prefix
- mapping: prefix
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: ip_namespace
- mapping: namespace
- reference: NautobotNamespace
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: status
- mapping: status
- reference: StatusGeneric
- - name: vlan
- mapping: vlan
- reference: InfraVLAN
- - name: locations
- mapping: locations
- reference: LocationGeneric
-
- - name: InfraIPAddress
- mapping: ipam.ip-addresses
- identifiers: ["address", "ip_prefix"]
- fields:
- - name: address
- mapping: address
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: ip_prefix
- mapping: parent
- reference: InfraPrefix
- - name: interfaces
- mapping: interfaces
- reference: InfraInterfaceL2L3
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: status
- mapping: status
- reference: StatusGeneric
-
- # Interfaces (interfaces, rear port, front port)
- - name: InfraInterfaceL2L3
- identifiers: ["name", "device"]
- mapping: dcim.interfaces
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: interface_type
- mapping: type.label
- - name: l2_mode
- mapping: mode.label
- - name: mac_address
- mapping: mac_address
- # - name: ip_addresses
- # mapping: ip_addresses
- # reference: InfraIPAddress
- - name: mgmt_only
- mapping: mgmt_only
- - name: untagged_vlan
- mapping: untagged_vlan
- reference: InfraVLAN
- - name: tagged_vlan
- mapping: tagged_vlans
- reference: InfraVLAN
- - name: device
- mapping: device
- reference: InfraDevice
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: status
- mapping: status
- reference: StatusGeneric
-
- - name: InfraFrontPort
- identifiers: ["name", "device"]
- mapping: dcim.front-ports
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: port_type
- mapping: type.label
- - name: rear_port
- mapping: rear_port
- reference: InfraRearPort
- - name: device
- mapping: device
- reference: InfraDevice
- - name: status
- mapping: status
- reference: StatusGeneric
- - name: InfraRearPort
- identifiers: ["name", "device"]
- mapping: dcim.rear-ports
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: port_type
- mapping: type.label
- - name: device
- mapping: device
- reference: InfraDevice
- - name: status
- mapping: status
- reference: StatusGeneric
diff --git a/sync/examples/nautobot-v2_to_infrahub/infrahub/sync_adapter.py b/sync/examples/nautobot-v2_to_infrahub/infrahub/sync_adapter.py
deleted file mode 100644
index 262d18de92..0000000000
--- a/sync/examples/nautobot-v2_to_infrahub/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,60 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- BuiltinTag,
- CoreStandardGroup,
- InfraAutonomousSystem,
- InfraCircuit,
- InfraDevice,
- InfraFrontPort,
- InfraInterfaceL2L3,
- InfraIPAddress,
- InfraPlatform,
- InfraPrefix,
- InfraProviderNetwork,
- InfraRack,
- InfraRearPort,
- InfraRouteTarget,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- NautobotNamespace,
- OrganizationGeneric,
- RoleGeneric,
- StatusGeneric,
- TemplateCircuitType,
- TemplateDeviceType,
- TemplateLocationType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- CoreStandardGroup = CoreStandardGroup
- BuiltinTag = BuiltinTag
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraCircuit = InfraCircuit
- InfraDevice = InfraDevice
- InfraFrontPort = InfraFrontPort
- InfraIPAddress = InfraIPAddress
- InfraInterfaceL2L3 = InfraInterfaceL2L3
- InfraPlatform = InfraPlatform
- InfraPrefix = InfraPrefix
- InfraProviderNetwork = InfraProviderNetwork
- InfraRack = InfraRack
- InfraRearPort = InfraRearPort
- InfraRouteTarget = InfraRouteTarget
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- NautobotNamespace = NautobotNamespace
- OrganizationGeneric = OrganizationGeneric
- RoleGeneric = RoleGeneric
- StatusGeneric = StatusGeneric
- TemplateCircuitType = TemplateCircuitType
- TemplateDeviceType = TemplateDeviceType
- TemplateLocationType = TemplateLocationType
diff --git a/sync/examples/nautobot-v2_to_infrahub/infrahub/sync_models.py b/sync/examples/nautobot-v2_to_infrahub/infrahub/sync_models.py
deleted file mode 100644
index 794f1bac2e..0000000000
--- a/sync/examples/nautobot-v2_to_infrahub/infrahub/sync_models.py
+++ /dev/null
@@ -1,356 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(InfrahubModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class BuiltinTag(InfrahubModel):
- _modelname = "BuiltinTag"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraAutonomousSystem(InfrahubModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("name",)
- _attributes = ("organization", "asn", "description")
- name: str
- asn: int
- description: Optional[str] = None
- organization: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraCircuit(InfrahubModel):
- _modelname = "InfraCircuit"
- _identifiers = ("circuit_id",)
- _attributes = ("status", "provider", "type", "tags", "description", "vendor_id")
- circuit_id: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- status: Optional[str] = None
- provider: str
- type: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(InfrahubModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "organization", "name")
- _attributes = ("model", "rack", "status", "role", "tags", "platform", "serial_number", "asset_tag")
- name: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- model: str
- rack: Optional[str] = None
- status: Optional[str] = None
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- platform: Optional[str] = None
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraFrontPort(InfrahubModel):
- _modelname = "InfraFrontPort"
- _identifiers = ("name", "device")
- _attributes = ("rear_port", "description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- rear_port: Optional[List[str]] = []
- device: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIPAddress(InfrahubModel):
- _modelname = "InfraIPAddress"
- _identifiers = ("address", "ip_prefix")
- _attributes = ("organization", "interfaces", "role", "description")
- address: str
- description: Optional[str] = None
- organization: Optional[str] = None
- interfaces: Optional[List[str]] = []
- role: Optional[str] = None
- ip_prefix: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL2L3(InfrahubModel):
- _modelname = "InfraInterfaceL2L3"
- _identifiers = ("name", "device")
- _attributes = (
- "tagged_vlan",
- "status",
- "tags",
- "l2_mode",
- "description",
- "mgmt_only",
- "mac_address",
- "interface_type",
- )
- l2_mode: Optional[str] = None
- name: str
- description: Optional[str] = None
- mgmt_only: Optional[bool] = False
- mac_address: Optional[str] = None
- interface_type: Optional[str] = None
- untagged_vlan: Optional[str] = None
- tagged_vlan: Optional[List[str]] = []
- status: Optional[str] = None
- device: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPlatform(InfrahubModel):
- _modelname = "InfraPlatform"
- _identifiers = ("name", "manufacturer")
- _attributes = ("description", "napalm_driver")
- name: str
- description: Optional[str] = None
- napalm_driver: Optional[str] = None
- manufacturer: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPrefix(InfrahubModel):
- _modelname = "InfraPrefix"
- _identifiers = ("prefix", "ip_namespace")
- _attributes = ("organization", "locations", "status", "role", "vlan", "description")
- prefix: str
- description: Optional[str] = None
- organization: Optional[str] = None
- locations: Optional[List[str]] = []
- status: Optional[str] = None
- role: Optional[str] = None
- vlan: Optional[str] = None
- ip_namespace: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraProviderNetwork(InfrahubModel):
- _modelname = "InfraProviderNetwork"
- _identifiers = ("name",)
- _attributes = ("status", "provider", "tags", "description", "vendor_id")
- name: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- status: Optional[str] = None
- provider: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRack(InfrahubModel):
- _modelname = "InfraRack"
- _identifiers = ("name",)
- _attributes = ("location", "role", "tags", "height", "facility_id", "serial_number", "asset_tag")
- name: str
- height: Optional[int] = None
- facility_id: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- role: Optional[str] = None
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRearPort(InfrahubModel):
- _modelname = "InfraRearPort"
- _identifiers = ("name", "device")
- _attributes = ("description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- device: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRouteTarget(InfrahubModel):
- _modelname = "InfraRouteTarget"
- _identifiers = ("name", "organization")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(InfrahubModel):
- _modelname = "InfraVLAN"
- _identifiers = ("name",)
- _attributes = ("organization", "locations", "status", "role", "vlan_group", "description", "vlan_id")
- name: str
- description: Optional[str] = None
- vlan_id: int
- organization: Optional[str] = None
- locations: Optional[List[str]] = []
- status: Optional[str] = None
- role: Optional[str] = None
- vlan_group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(InfrahubModel):
- _modelname = "InfraVRF"
- _identifiers = ("name", "ip_namespace")
- _attributes = ("organization", "import_rt", "export_rt", "description", "vrf_rd")
- name: str
- description: Optional[str] = None
- vrf_rd: Optional[str] = None
- organization: Optional[str] = None
- ip_namespace: str
- import_rt: Optional[List[str]] = []
- export_rt: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(InfrahubModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("tags", "location_type", "status", "description")
- name: str
- description: Optional[str] = None
- tags: Optional[List[str]] = []
- location_type: Optional[str] = None
- status: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class NautobotNamespace(InfrahubModel):
- _modelname = "NautobotNamespace"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class OrganizationGeneric(InfrahubModel):
- _modelname = "OrganizationGeneric"
- _identifiers = ("name",)
- _attributes = ("group", "description", "type")
- name: str
- description: Optional[str] = None
- type: Optional[str] = None
- group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class RoleGeneric(InfrahubModel):
- _modelname = "RoleGeneric"
- _identifiers = ("name",)
- _attributes = ("label", "description")
- name: str
- label: Optional[str] = None
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class StatusGeneric(InfrahubModel):
- _modelname = "StatusGeneric"
- _identifiers = ("name",)
- _attributes = ("label", "description")
- name: str
- label: Optional[str] = None
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateCircuitType(InfrahubModel):
- _modelname = "TemplateCircuitType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(InfrahubModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("tags", "part_number", "height", "full_depth")
- part_number: Optional[str] = None
- height: Optional[int] = None
- full_depth: Optional[bool] = None
- name: str
- manufacturer: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateLocationType(InfrahubModel):
- _modelname = "TemplateLocationType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/nautobot-v2_to_infrahub/nautobot/sync_adapter.py b/sync/examples/nautobot-v2_to_infrahub/nautobot/sync_adapter.py
deleted file mode 100644
index 51cc3ac57f..0000000000
--- a/sync/examples/nautobot-v2_to_infrahub/nautobot/sync_adapter.py
+++ /dev/null
@@ -1,60 +0,0 @@
-from infrahub_sync.adapters.nautobot import NautobotAdapter
-
-from .sync_models import (
- BuiltinTag,
- CoreStandardGroup,
- InfraAutonomousSystem,
- InfraCircuit,
- InfraDevice,
- InfraFrontPort,
- InfraInterfaceL2L3,
- InfraIPAddress,
- InfraPlatform,
- InfraPrefix,
- InfraProviderNetwork,
- InfraRack,
- InfraRearPort,
- InfraRouteTarget,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- NautobotNamespace,
- OrganizationGeneric,
- RoleGeneric,
- StatusGeneric,
- TemplateCircuitType,
- TemplateDeviceType,
- TemplateLocationType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class NautobotSync(NautobotAdapter):
- CoreStandardGroup = CoreStandardGroup
- BuiltinTag = BuiltinTag
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraCircuit = InfraCircuit
- InfraDevice = InfraDevice
- InfraFrontPort = InfraFrontPort
- InfraIPAddress = InfraIPAddress
- InfraInterfaceL2L3 = InfraInterfaceL2L3
- InfraPlatform = InfraPlatform
- InfraPrefix = InfraPrefix
- InfraProviderNetwork = InfraProviderNetwork
- InfraRack = InfraRack
- InfraRearPort = InfraRearPort
- InfraRouteTarget = InfraRouteTarget
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- NautobotNamespace = NautobotNamespace
- OrganizationGeneric = OrganizationGeneric
- RoleGeneric = RoleGeneric
- StatusGeneric = StatusGeneric
- TemplateCircuitType = TemplateCircuitType
- TemplateDeviceType = TemplateDeviceType
- TemplateLocationType = TemplateLocationType
diff --git a/sync/examples/nautobot-v2_to_infrahub/nautobot/sync_models.py b/sync/examples/nautobot-v2_to_infrahub/nautobot/sync_models.py
deleted file mode 100644
index 3610f3cae3..0000000000
--- a/sync/examples/nautobot-v2_to_infrahub/nautobot/sync_models.py
+++ /dev/null
@@ -1,356 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.nautobot import NautobotModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(NautobotModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class BuiltinTag(NautobotModel):
- _modelname = "BuiltinTag"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraAutonomousSystem(NautobotModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("name",)
- _attributes = ("organization", "asn", "description")
- name: str
- asn: int
- description: Optional[str] = None
- organization: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraCircuit(NautobotModel):
- _modelname = "InfraCircuit"
- _identifiers = ("circuit_id",)
- _attributes = ("status", "provider", "type", "tags", "description", "vendor_id")
- circuit_id: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- status: Optional[str] = None
- provider: str
- type: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(NautobotModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "organization", "name")
- _attributes = ("model", "rack", "status", "role", "tags", "platform", "serial_number", "asset_tag")
- name: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- model: str
- rack: Optional[str] = None
- status: Optional[str] = None
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- platform: Optional[str] = None
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraFrontPort(NautobotModel):
- _modelname = "InfraFrontPort"
- _identifiers = ("name", "device")
- _attributes = ("rear_port", "description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- rear_port: Optional[List[str]] = []
- device: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIPAddress(NautobotModel):
- _modelname = "InfraIPAddress"
- _identifiers = ("address", "ip_prefix")
- _attributes = ("organization", "interfaces", "role", "description")
- address: str
- description: Optional[str] = None
- organization: Optional[str] = None
- interfaces: Optional[List[str]] = []
- role: Optional[str] = None
- ip_prefix: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL2L3(NautobotModel):
- _modelname = "InfraInterfaceL2L3"
- _identifiers = ("name", "device")
- _attributes = (
- "tagged_vlan",
- "status",
- "tags",
- "l2_mode",
- "description",
- "mgmt_only",
- "mac_address",
- "interface_type",
- )
- l2_mode: Optional[str] = None
- name: str
- description: Optional[str] = None
- mgmt_only: Optional[bool] = False
- mac_address: Optional[str] = None
- interface_type: Optional[str] = None
- untagged_vlan: Optional[str] = None
- tagged_vlan: Optional[List[str]] = []
- status: Optional[str] = None
- device: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPlatform(NautobotModel):
- _modelname = "InfraPlatform"
- _identifiers = ("name", "manufacturer")
- _attributes = ("description", "napalm_driver")
- name: str
- description: Optional[str] = None
- napalm_driver: Optional[str] = None
- manufacturer: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPrefix(NautobotModel):
- _modelname = "InfraPrefix"
- _identifiers = ("prefix", "ip_namespace")
- _attributes = ("organization", "locations", "status", "role", "vlan", "description")
- prefix: str
- description: Optional[str] = None
- organization: Optional[str] = None
- locations: Optional[List[str]] = []
- status: Optional[str] = None
- role: Optional[str] = None
- vlan: Optional[str] = None
- ip_namespace: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraProviderNetwork(NautobotModel):
- _modelname = "InfraProviderNetwork"
- _identifiers = ("name",)
- _attributes = ("status", "provider", "tags", "description", "vendor_id")
- name: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- status: Optional[str] = None
- provider: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRack(NautobotModel):
- _modelname = "InfraRack"
- _identifiers = ("name",)
- _attributes = ("location", "role", "tags", "height", "facility_id", "serial_number", "asset_tag")
- name: str
- height: Optional[int] = None
- facility_id: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- role: Optional[str] = None
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRearPort(NautobotModel):
- _modelname = "InfraRearPort"
- _identifiers = ("name", "device")
- _attributes = ("description", "port_type")
- name: str
- description: Optional[str] = None
- port_type: Optional[str] = None
- device: str
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRouteTarget(NautobotModel):
- _modelname = "InfraRouteTarget"
- _identifiers = ("name", "organization")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(NautobotModel):
- _modelname = "InfraVLAN"
- _identifiers = ("name",)
- _attributes = ("organization", "locations", "status", "role", "vlan_group", "description", "vlan_id")
- name: str
- description: Optional[str] = None
- vlan_id: int
- organization: Optional[str] = None
- locations: Optional[List[str]] = []
- status: Optional[str] = None
- role: Optional[str] = None
- vlan_group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(NautobotModel):
- _modelname = "InfraVRF"
- _identifiers = ("name", "ip_namespace")
- _attributes = ("organization", "import_rt", "export_rt", "description", "vrf_rd")
- name: str
- description: Optional[str] = None
- vrf_rd: Optional[str] = None
- organization: Optional[str] = None
- ip_namespace: str
- import_rt: Optional[List[str]] = []
- export_rt: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(NautobotModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("tags", "location_type", "status", "description")
- name: str
- description: Optional[str] = None
- tags: Optional[List[str]] = []
- location_type: Optional[str] = None
- status: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class NautobotNamespace(NautobotModel):
- _modelname = "NautobotNamespace"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class OrganizationGeneric(NautobotModel):
- _modelname = "OrganizationGeneric"
- _identifiers = ("name",)
- _attributes = ("group", "description", "type")
- name: str
- description: Optional[str] = None
- type: Optional[str] = None
- group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class RoleGeneric(NautobotModel):
- _modelname = "RoleGeneric"
- _identifiers = ("name",)
- _attributes = ("label", "description")
- name: str
- label: Optional[str] = None
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class StatusGeneric(NautobotModel):
- _modelname = "StatusGeneric"
- _identifiers = ("name",)
- _attributes = ("label", "description")
- name: str
- label: Optional[str] = None
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateCircuitType(NautobotModel):
- _modelname = "TemplateCircuitType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(NautobotModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("tags", "part_number", "height", "full_depth")
- part_number: Optional[str] = None
- height: Optional[int] = None
- full_depth: Optional[bool] = None
- name: str
- manufacturer: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateLocationType(NautobotModel):
- _modelname = "TemplateLocationType"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/netbox_to_infrahub/config.yml b/sync/examples/netbox_to_infrahub/config.yml
deleted file mode 100644
index ea99b56f43..0000000000
--- a/sync/examples/netbox_to_infrahub/config.yml
+++ /dev/null
@@ -1,466 +0,0 @@
----
-name: from-netbox
-
-source:
- name: netbox
- settings:
- url: "https://demo.netbox.dev"
- token: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-
-destination:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-order: [
- "BuiltinTag",
- "RoleGeneric",
- "CoreStandardGroup",
- "OrganizationGeneric",
- "LocationGeneric",
- "InfraRack",
- "TemplateDeviceType",
- "InfraProviderNetwork",
- "TemplateCircuitType",
- "InfraCircuit",
- "InfraRouteTarget",
- "InfraVRF",
- "InfraDevice",
- "InfraVLAN",
- "InfraPrefix",
- # "InfraIPAddress",
- # "InfraInterfaceL2L3",
-]
-
-schema_mapping:
- # Tags
- - name: BuiltinTag
- mapping: extras.tags
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
-
- # Roles (DCIM, IPAM, Devices)
- - name: RoleGeneric
- mapping: dcim.device_roles
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: RoleGeneric
- mapping: dcim.rack_roles
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: RoleGeneric
- mapping: ipam.roles
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
-
- # Tenancy (tenants, tenant groups)
- - name: CoreStandardGroup
- mapping: tenancy.tenant-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: OrganizationGeneric
- mapping: tenancy.tenants
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: group
- mapping: group
- reference: CoreStandardGroup
-
- # Sites (Site Groups, Region, Sites, Location)
- - name: CoreStandardGroup
- mapping: dcim.site-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: LocationGeneric
- mapping: dcim.regions
- fields:
- - name: name
- mapping: slug
- - name: description
- mapping: name
- - name: type
- static: "Region"
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: LocationGeneric
- mapping: dcim.sites
- fields:
- - name: name
- mapping: slug
- - name: description
- mapping: name
- - name: type
- static: "Site"
- - name: group
- mapping: group
- reference: CoreStandardGroup
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: LocationGeneric
- mapping: dcim.locations
- fields:
- - name: name
- mapping: slug
- - name: description
- mapping: name
- - name: type
- static: "Location"
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # Racks
- - name: InfraRack
- mapping: dcim.racks
- identifiers: ["name", "location"]
- fields:
- - name: name
- mapping: name
- - name: location
- mapping: site
- reference: LocationGeneric
- - name: height
- mapping: u_height
- - name: serial_number
- mapping: serial
- - name: asset_tag
- mapping: asset_tag
- - name: facility_id
- mapping: facility_id
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
- # Device (manufacturer, device types, devices, interfaces)
- - name: OrganizationGeneric
- mapping: dcim.manufacturers
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: TemplateDeviceType
- mapping: dcim.device-types
- identifiers: ["name", "manufacturer"]
- fields:
- - name: name
- mapping: model
- - name: part_number
- mapping: part_number
- - name: full_depth
- mapping: is_full_depth
- - name: height
- mapping: integer_height
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: manufacturer
- mapping: manufacturer
- reference: OrganizationGeneric
- transforms:
- - field: integer_height
- expression: "{{ u_height|float|round(0, 'ceil') }}"
- # -> The netbox constraint is `dcim_device_unique_name_site_tenant`
- # Reusing device_name + site + Organization as identifiers
- # /!\ Seem like Netbox allowed device to have the same name if there is a virtual-chassis
- - name: InfraDevice
- identifiers: ["location", "rack", "organization", "name"]
- mapping: dcim.devices
- fields:
- - name: name
- mapping: name
- - name: serial_number
- mapping: serial
- - name: asset_tag
- mapping: asset_tag
- - name: description
- mapping: description
- - name: model
- mapping: device_type
- reference: TemplateDeviceType
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: role
- mapping: role
- reference: RoleGeneric
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: location
- mapping: site
- reference: LocationGeneric
- - name: rack
- mapping: rack
- reference: InfraRack
- - name: tags
- mapping: tags
- reference: BuiltinTag
- # Showcase Filters
- # It will import the ones with dmu01 in their name *AND* without pdu
- filters:
- - field: name
- operation: "contains"
- value: "dmi01"
- - field: name
- operation: "not contains"
- value: "pdu"
- # Showcase Transforms
- transforms:
- - field: name
- expression: "{{ name.lower() }}"
- - field: serial_number
- expression: "{{ serial_number.lower() if serial_number else '' }}}"
-
- # Interfaces (interfaces, rear port, front port)
- - name: InfraInterfaceL2L3
- identifiers: ["device", "name"]
- mapping: dcim.interfaces
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: interface_type
- mapping: type.label
- - name: l2_mode
- mapping: mode.label
- - name: mac_address
- mapping: mac_address
- # - name: ip_addresses
- # mapping: ip_addresses
- # reference: InfraIPAddress
- - name: mgmt_only
- mapping: mgmt_only
- - name: untagged_vlan
- mapping: untagged_vlan
- reference: InfraVLAN
- - name: tagged_vlan
- mapping: tagged_vlans
- reference: InfraVLAN
- - name: device
- mapping: device
- reference: InfraDevice
- - name: tags
- mapping: tags
- reference: BuiltinTag
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- filters:
- - field: device.name
- operation: "contains"
- value: "dmi01"
-
- # Circuits (Provider, Provider Network, Circuits Types, Circuits)
- - name: OrganizationGeneric
- mapping: circuits.providers
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: InfraProviderNetwork
- mapping: circuits.provider-networks
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: vendor_id
- mapping: service_id
- - name: provider
- mapping: provider
- reference: OrganizationGeneric
- - name: description
- mapping: description
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: provider
- mapping: provider
- reference: OrganizationGeneric
- - name: TemplateCircuitType
- mapping: circuits.circuit-types
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: tags
- mapping: tags
- reference: BuiltinTag
- - name: InfraCircuit
- mapping: circuits.circuits
- identifiers: ["circuit_id"]
- fields:
- - name: circuit_id
- mapping: cid
- - name: vendor_id
- mapping: cid
- - name: provider
- mapping: provider
- reference: OrganizationGeneric
- - name: description
- mapping: description
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: type
- mapping: type.name
- - name: provider
- mapping: provider
- reference: OrganizationGeneric
- - name: tags
- mapping: tags
- reference: BuiltinTag
-
-# IPAM (VRF, VLANs Groups, VLANs, Prefixes, IPs)
- - name: InfraRouteTarget
- mapping: ipam.route-targets
- identifiers: ["name", "organization"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: InfraVRF
- mapping: ipam.vrfs
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: vrf_rd
- mapping: rd
- - name: import_rt
- mapping: import_targets
- reference: InfraRouteTarget
- - name: export_rt
- mapping: export_targets
- reference: InfraRouteTarget
- - name: CoreStandardGroup
- mapping: ipam.vlan-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: InfraVLAN
- mapping: ipam.vlans
- identifiers: ["name", "vlan_id", "location", "vlan_group"]
- fields:
- - name: name
- mapping: name
- - name: vlan_id
- mapping: vid
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: description
- mapping: description
- - name: location
- mapping: site
- reference: LocationGeneric
- - name: vlan_group
- mapping: group
- reference: CoreStandardGroup
- - name: InfraPrefix
- mapping: ipam.prefixes
- identifiers: ["prefix", "vrf"]
- fields:
- - name: prefix
- mapping: prefix
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- - name: role
- mapping: role
- reference: RoleGeneric
- - name: vrf
- mapping: vrf
- reference: InfraVRF
- - name: location
- mapping: site
- reference: LocationGeneric
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- # - name: vlan
- # mapping: vlan.name
- # - name: location
- # mapping: location.slug
- - name: InfraIPAddress
- mapping: ipam.ip-addresses
- identifiers: ["address", "vrf"]
- fields:
- - name: address
- mapping: address
- - name: description
- mapping: description
- - name: organization
- mapping: tenant
- reference: OrganizationGeneric
- # Not the same as ipam.role
- # - name: role
- # mapping: role.value
- # - name: status
- # mapping: status
- # reference: StatusGeneric
- - name: vrf
- mapping: vrf
- reference: InfraVRF
diff --git a/sync/examples/netbox_to_infrahub/infrahub/sync_adapter.py b/sync/examples/netbox_to_infrahub/infrahub/sync_adapter.py
deleted file mode 100644
index d15c7162c7..0000000000
--- a/sync/examples/netbox_to_infrahub/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- BuiltinTag,
- CoreStandardGroup,
- InfraCircuit,
- InfraDevice,
- InfraInterfaceL2L3,
- InfraIPAddress,
- InfraPrefix,
- InfraProviderNetwork,
- InfraRack,
- InfraRouteTarget,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- OrganizationGeneric,
- RoleGeneric,
- TemplateCircuitType,
- TemplateDeviceType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- CoreStandardGroup = CoreStandardGroup
- BuiltinTag = BuiltinTag
- InfraCircuit = InfraCircuit
- InfraDevice = InfraDevice
- InfraIPAddress = InfraIPAddress
- InfraInterfaceL2L3 = InfraInterfaceL2L3
- InfraPrefix = InfraPrefix
- InfraProviderNetwork = InfraProviderNetwork
- InfraRack = InfraRack
- InfraRouteTarget = InfraRouteTarget
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- OrganizationGeneric = OrganizationGeneric
- RoleGeneric = RoleGeneric
- TemplateCircuitType = TemplateCircuitType
- TemplateDeviceType = TemplateDeviceType
diff --git a/sync/examples/netbox_to_infrahub/infrahub/sync_models.py b/sync/examples/netbox_to_infrahub/infrahub/sync_models.py
deleted file mode 100644
index 40d3811411..0000000000
--- a/sync/examples/netbox_to_infrahub/infrahub/sync_models.py
+++ /dev/null
@@ -1,249 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(InfrahubModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class BuiltinTag(InfrahubModel):
- _modelname = "BuiltinTag"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraCircuit(InfrahubModel):
- _modelname = "InfraCircuit"
- _identifiers = ("circuit_id",)
- _attributes = ("provider", "type", "tags", "description", "vendor_id")
- circuit_id: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- type: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(InfrahubModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "rack", "organization", "name")
- _attributes = ("model", "role", "tags", "description", "serial_number", "asset_tag")
- name: Optional[str] = None
- description: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- model: str
- rack: Optional[str] = None
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIPAddress(InfrahubModel):
- _modelname = "InfraIPAddress"
- _identifiers = ("address", "vrf")
- _attributes = ("organization", "description")
- address: str
- description: Optional[str] = None
- organization: Optional[str] = None
- vrf: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL2L3(InfrahubModel):
- _modelname = "InfraInterfaceL2L3"
- _identifiers = ("device", "name")
- _attributes = ("tagged_vlan", "tags", "l2_mode", "description", "mgmt_only", "mac_address", "interface_type")
- l2_mode: Optional[str] = None
- name: str
- description: Optional[str] = None
- mgmt_only: Optional[bool] = False
- mac_address: Optional[str] = None
- interface_type: Optional[str] = None
- untagged_vlan: Optional[str] = None
- tagged_vlan: Optional[List[str]] = []
- device: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPrefix(InfrahubModel):
- _modelname = "InfraPrefix"
- _identifiers = ("prefix", "vrf")
- _attributes = ("organization", "location", "role", "description")
- prefix: str
- description: Optional[str] = None
- organization: Optional[str] = None
- location: Optional[str] = None
- role: Optional[str] = None
- vrf: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraProviderNetwork(InfrahubModel):
- _modelname = "InfraProviderNetwork"
- _identifiers = ("name",)
- _attributes = ("provider", "tags", "description", "vendor_id")
- name: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRack(InfrahubModel):
- _modelname = "InfraRack"
- _identifiers = ("name", "location")
- _attributes = ("role", "tags", "height", "facility_id", "serial_number", "asset_tag")
- name: str
- height: Optional[int] = None
- facility_id: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- role: Optional[str] = None
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRouteTarget(InfrahubModel):
- _modelname = "InfraRouteTarget"
- _identifiers = ("name", "organization")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(InfrahubModel):
- _modelname = "InfraVLAN"
- _identifiers = ("name", "vlan_id", "location", "vlan_group")
- _attributes = ("organization", "description")
- name: str
- description: Optional[str] = None
- vlan_id: int
- organization: Optional[str] = None
- location: Optional[str] = None
- vlan_group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(InfrahubModel):
- _modelname = "InfraVRF"
- _identifiers = ("name",)
- _attributes = ("organization", "import_rt", "export_rt", "description", "vrf_rd")
- name: str
- description: Optional[str] = None
- vrf_rd: Optional[str] = None
- organization: Optional[str] = None
- import_rt: Optional[List[str]] = []
- export_rt: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(InfrahubModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("organization", "tags", "group", "description", "type")
- name: str
- description: Optional[str] = None
- type: str
- organization: Optional[str] = None
- tags: Optional[List[str]] = []
- group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class OrganizationGeneric(InfrahubModel):
- _modelname = "OrganizationGeneric"
- _identifiers = ("name",)
- _attributes = ("group", "description")
- name: str
- description: Optional[str] = None
- group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class RoleGeneric(InfrahubModel):
- _modelname = "RoleGeneric"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateCircuitType(InfrahubModel):
- _modelname = "TemplateCircuitType"
- _identifiers = ("name",)
- _attributes = ("tags", "description")
- name: str
- description: Optional[str] = None
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(InfrahubModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("tags", "part_number", "height", "full_depth")
- part_number: Optional[str] = None
- height: Optional[int] = None
- full_depth: Optional[bool] = None
- name: str
- manufacturer: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/netbox_to_infrahub/netbox/__init__.py b/sync/examples/netbox_to_infrahub/netbox/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/sync/examples/netbox_to_infrahub/netbox/sync_adapter.py b/sync/examples/netbox_to_infrahub/netbox/sync_adapter.py
deleted file mode 100644
index fb564be65c..0000000000
--- a/sync/examples/netbox_to_infrahub/netbox/sync_adapter.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from infrahub_sync.adapters.netbox import NetboxAdapter
-
-from .sync_models import (
- BuiltinTag,
- CoreStandardGroup,
- InfraCircuit,
- InfraDevice,
- InfraInterfaceL2L3,
- InfraIPAddress,
- InfraPrefix,
- InfraProviderNetwork,
- InfraRack,
- InfraRouteTarget,
- InfraVLAN,
- InfraVRF,
- LocationGeneric,
- OrganizationGeneric,
- RoleGeneric,
- TemplateCircuitType,
- TemplateDeviceType,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class NetboxSync(NetboxAdapter):
- CoreStandardGroup = CoreStandardGroup
- BuiltinTag = BuiltinTag
- InfraCircuit = InfraCircuit
- InfraDevice = InfraDevice
- InfraIPAddress = InfraIPAddress
- InfraInterfaceL2L3 = InfraInterfaceL2L3
- InfraPrefix = InfraPrefix
- InfraProviderNetwork = InfraProviderNetwork
- InfraRack = InfraRack
- InfraRouteTarget = InfraRouteTarget
- InfraVLAN = InfraVLAN
- InfraVRF = InfraVRF
- LocationGeneric = LocationGeneric
- OrganizationGeneric = OrganizationGeneric
- RoleGeneric = RoleGeneric
- TemplateCircuitType = TemplateCircuitType
- TemplateDeviceType = TemplateDeviceType
diff --git a/sync/examples/netbox_to_infrahub/netbox/sync_models.py b/sync/examples/netbox_to_infrahub/netbox/sync_models.py
deleted file mode 100644
index f8d5929629..0000000000
--- a/sync/examples/netbox_to_infrahub/netbox/sync_models.py
+++ /dev/null
@@ -1,249 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.netbox import NetboxModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(NetboxModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class BuiltinTag(NetboxModel):
- _modelname = "BuiltinTag"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraCircuit(NetboxModel):
- _modelname = "InfraCircuit"
- _identifiers = ("circuit_id",)
- _attributes = ("provider", "type", "tags", "description", "vendor_id")
- circuit_id: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- type: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(NetboxModel):
- _modelname = "InfraDevice"
- _identifiers = ("location", "rack", "organization", "name")
- _attributes = ("model", "role", "tags", "description", "serial_number", "asset_tag")
- name: Optional[str] = None
- description: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- model: str
- rack: Optional[str] = None
- role: Optional[str] = None
- tags: Optional[List[str]] = []
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIPAddress(NetboxModel):
- _modelname = "InfraIPAddress"
- _identifiers = ("address", "vrf")
- _attributes = ("organization", "description")
- address: str
- description: Optional[str] = None
- organization: Optional[str] = None
- vrf: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraInterfaceL2L3(NetboxModel):
- _modelname = "InfraInterfaceL2L3"
- _identifiers = ("device", "name")
- _attributes = ("tagged_vlan", "tags", "l2_mode", "description", "mgmt_only", "mac_address", "interface_type")
- l2_mode: Optional[str] = None
- name: str
- description: Optional[str] = None
- mgmt_only: Optional[bool] = False
- mac_address: Optional[str] = None
- interface_type: Optional[str] = None
- untagged_vlan: Optional[str] = None
- tagged_vlan: Optional[List[str]] = []
- device: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraPrefix(NetboxModel):
- _modelname = "InfraPrefix"
- _identifiers = ("prefix", "vrf")
- _attributes = ("organization", "location", "role", "description")
- prefix: str
- description: Optional[str] = None
- organization: Optional[str] = None
- location: Optional[str] = None
- role: Optional[str] = None
- vrf: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraProviderNetwork(NetboxModel):
- _modelname = "InfraProviderNetwork"
- _identifiers = ("name",)
- _attributes = ("provider", "tags", "description", "vendor_id")
- name: str
- description: Optional[str] = None
- vendor_id: Optional[str] = None
- provider: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRack(NetboxModel):
- _modelname = "InfraRack"
- _identifiers = ("name", "location")
- _attributes = ("role", "tags", "height", "facility_id", "serial_number", "asset_tag")
- name: str
- height: Optional[int] = None
- facility_id: Optional[str] = None
- serial_number: Optional[str] = None
- asset_tag: Optional[str] = None
- location: str
- role: Optional[str] = None
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraRouteTarget(NetboxModel):
- _modelname = "InfraRouteTarget"
- _identifiers = ("name", "organization")
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
- organization: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVLAN(NetboxModel):
- _modelname = "InfraVLAN"
- _identifiers = ("name", "vlan_id", "location", "vlan_group")
- _attributes = ("organization", "description")
- name: str
- description: Optional[str] = None
- vlan_id: int
- organization: Optional[str] = None
- location: Optional[str] = None
- vlan_group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraVRF(NetboxModel):
- _modelname = "InfraVRF"
- _identifiers = ("name",)
- _attributes = ("organization", "import_rt", "export_rt", "description", "vrf_rd")
- name: str
- description: Optional[str] = None
- vrf_rd: Optional[str] = None
- organization: Optional[str] = None
- import_rt: Optional[List[str]] = []
- export_rt: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class LocationGeneric(NetboxModel):
- _modelname = "LocationGeneric"
- _identifiers = ("name",)
- _attributes = ("organization", "tags", "group", "description", "type")
- name: str
- description: Optional[str] = None
- type: str
- organization: Optional[str] = None
- tags: Optional[List[str]] = []
- group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class OrganizationGeneric(NetboxModel):
- _modelname = "OrganizationGeneric"
- _identifiers = ("name",)
- _attributes = ("group", "description")
- name: str
- description: Optional[str] = None
- group: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class RoleGeneric(NetboxModel):
- _modelname = "RoleGeneric"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateCircuitType(NetboxModel):
- _modelname = "TemplateCircuitType"
- _identifiers = ("name",)
- _attributes = ("tags", "description")
- name: str
- description: Optional[str] = None
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class TemplateDeviceType(NetboxModel):
- _modelname = "TemplateDeviceType"
- _identifiers = ("name", "manufacturer")
- _attributes = ("tags", "part_number", "height", "full_depth")
- part_number: Optional[str] = None
- height: Optional[int] = None
- full_depth: Optional[bool] = None
- name: str
- manufacturer: str
- tags: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/observium_to_infrahub/config.yml b/sync/examples/observium_to_infrahub/config.yml
deleted file mode 100644
index 5bb8d75643..0000000000
--- a/sync/examples/observium_to_infrahub/config.yml
+++ /dev/null
@@ -1,90 +0,0 @@
----
-name: from-observium
-source:
- name: observium
- settings:
- url: "OBSERVIUM_URL"
- # api_endpoint: "api/v0"
- # auth_method: "basic"
- username: "OBSERVIUM_USERNAME"
- password: "OBSERVIUM_PASSWORD"
-
-destination:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-order: [
- "CoreStandardGroup",
- "IpamIPAddress",
- "InfraDevice",
-]
-
-schema_mapping:
- - name: CoreStandardGroup
- mapping: groups
- fields:
- - name: name
- mapping: group_name
- - name: description
- mapping: group_descr
-
- # Primary Device IP
- - name: IpamIPAddress
- mapping: devices
- identifiers: ["address"]
- fields:
- - name: address
- mapping: ip
- - name: description
- # We are using the field created via the transforms
- mapping: new_description
- filters:
- - field: hostname
- operation: regex
- value: "^pe-[0-9]{3}$"
- - field: ip
- operation: is_ip_within
- value: "10.0.0.0/8"
- transforms:
- - field: new_description
- expression: "{{ hostname | upper | replace('.', '-') }}"
-
- - name: InfraDevice
- mapping: devices
- identifiers: ["name"]
- fields:
- - name: name
- mapping: hostname
- - name: description
- mapping: description
- - name: description
- mapping: upper_serial
- # /!\ Platform need to exist beforehand !
- - name: platform
- mapping: os
- reference: InfraPlatform
- # /!\ Manufacturer need to exist beforehand !
- - name: manufacturer
- mapping: vendor
- reference: OrganizationManufacturer
- - name: type
- mapping: unknown_hardware
- - name: primary_address
- mapping: ip
- reference: IpamIPAddress
- filters:
- - field: device_id
- operation: ">"
- value: 100
- - field: device_id
- operation: "<="
- value: 200
- - field: hostname
- operation: regex
- value: "^pe-[0-9]{3}$"
- transforms:
- - field: upper_serial
- expression: "{{ serial.upper() if serial else '' }}"
- - field: unknown_hardware
- expression: "{{ hardware if hardware else 'unknown' }}"
diff --git a/sync/examples/observium_to_infrahub/infrahub/__init__.py b/sync/examples/observium_to_infrahub/infrahub/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/sync/examples/observium_to_infrahub/infrahub/sync_adapter.py b/sync/examples/observium_to_infrahub/infrahub/sync_adapter.py
deleted file mode 100644
index f9b8639335..0000000000
--- a/sync/examples/observium_to_infrahub/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- CoreStandardGroup,
- InfraDevice,
- IpamIPAddress,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- CoreStandardGroup = CoreStandardGroup
- InfraDevice = InfraDevice
- IpamIPAddress = IpamIPAddress
diff --git a/sync/examples/observium_to_infrahub/infrahub/sync_models.py b/sync/examples/observium_to_infrahub/infrahub/sync_models.py
deleted file mode 100644
index 4b0ff12b25..0000000000
--- a/sync/examples/observium_to_infrahub/infrahub/sync_models.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from typing import Any, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(InfrahubModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(InfrahubModel):
- _modelname = "InfraDevice"
- _identifiers = ("name",)
- _attributes = ("primary_address", "platform", "description", "type")
- name: str
- description: Optional[str] = None
- type: str
- primary_address: Optional[str] = None
- platform: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class IpamIPAddress(InfrahubModel):
- _modelname = "IpamIPAddress"
- _identifiers = ("address",)
- _attributes = ("description",)
- address: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/observium_to_infrahub/observium/__init__.py b/sync/examples/observium_to_infrahub/observium/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/sync/examples/observium_to_infrahub/observium/sync_adapter.py b/sync/examples/observium_to_infrahub/observium/sync_adapter.py
deleted file mode 100644
index 9edf6bf911..0000000000
--- a/sync/examples/observium_to_infrahub/observium/sync_adapter.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from infrahub_sync.adapters.observium import ObserviumAdapter
-
-from .sync_models import (
- CoreStandardGroup,
- InfraDevice,
- IpamIPAddress,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class ObserviumSync(ObserviumAdapter):
- CoreStandardGroup = CoreStandardGroup
- InfraDevice = InfraDevice
- IpamIPAddress = IpamIPAddress
diff --git a/sync/examples/observium_to_infrahub/observium/sync_models.py b/sync/examples/observium_to_infrahub/observium/sync_models.py
deleted file mode 100644
index 10cee57928..0000000000
--- a/sync/examples/observium_to_infrahub/observium/sync_models.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from typing import Any, Optional
-
-from infrahub_sync.adapters.observium import ObserviumModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class CoreStandardGroup(ObserviumModel):
- _modelname = "CoreStandardGroup"
- _identifiers = ("name",)
- _attributes = ("description",)
- name: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraDevice(ObserviumModel):
- _modelname = "InfraDevice"
- _identifiers = ("name",)
- _attributes = ("primary_address", "platform", "description", "type")
- name: str
- description: Optional[str] = None
- type: str
- primary_address: Optional[str] = None
- platform: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class IpamIPAddress(ObserviumModel):
- _modelname = "IpamIPAddress"
- _identifiers = ("address",)
- _attributes = ("description",)
- address: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/peering-manager_to_infrahub/config.yml b/sync/examples/peering-manager_to_infrahub/config.yml
deleted file mode 100644
index f74ef36089..0000000000
--- a/sync/examples/peering-manager_to_infrahub/config.yml
+++ /dev/null
@@ -1,190 +0,0 @@
----
-name: from-peering-manager
-source:
- name: peeringmanager
- settings:
- url: "https://demo.peering-manager.net"
- # api_endpoint: "api"
- # auth_method: "token"
- token: "13bf6338aed52d172e33750d39717fff5a5f5d18"
-
-destination:
- name: infrahub
- settings:
- url: "http://localhost:8000"
-
-order: [
- "InfraAutonomousSystem",
- "InfraBGPCommunity",
- "InfraBGPRoutingPolicy",
- "InfraBGPPeerGroup",
- "InfraIXP",
- "IpamIPAddress",
- "InfraIXPConnection",
-]
-
-schema_mapping:
- - name: InfraAutonomousSystem
- mapping: peering/autonomous-systems
- identifiers: ["asn"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: display
- - name: asn
- mapping: asn
- - name: irr_as_set
- mapping: irr_as_set
- - name: ipv4_max_prefixes
- mapping: ipv4_max_prefixes
- - name: ipv6_max_prefixes
- mapping: ipv6_max_prefixes
- - name: affiliated
- mapping: affiliated
-
- - name: InfraBGPCommunity
- mapping: peering/communities
- identifiers: ["name"]
- fields:
- - name: name
- mapping: slug
- - name: label
- mapping: name
- - name: description
- mapping: description
- - name: value
- mapping: value
- - name: community_type
- mapping: type
-
-
- - name: InfraBGPRoutingPolicy
- mapping: peering/routing-policies
- identifiers: ["name"]
- fields:
- - name: name
- mapping: slug
- - name: label
- mapping: name
- - name: description
- mapping: description
- - name: policy_type
- mapping: type
- - name: weight
- mapping: weight
- - name: address_family
- mapping: address_family
- - name: bgp_communities
- mapping: communities
- reference: InfraBGPCommunity
-
- - name: InfraBGPPeerGroup
- mapping: peering/bgp-groups
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: status
- mapping: status.value
- - name: import_policies
- mapping: import_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: export_policies
- mapping: export_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: bgp_communities
- mapping: communities
- reference: InfraBGPCommunity
-
- - name: InfraIXP
- mapping: peering/internet-exchanges
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: description
- mapping: description
- - name: status
- mapping: status.value
- - name: import_policies
- mapping: import_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: export_policies
- mapping: export_routing_policies
- reference: InfraBGPRoutingPolicy
- - name: bgp_communities
- mapping: communities
- reference: InfraBGPCommunity
- # Showcase Filters
- filters:
- - field: name
- operation: "is_not_empty"
- - field: status.value
- operation: contains
- value: "enabled"
- - field: name
- operation: contains
- value: "S.H.I.E.L.D"
- # Showcase Transforms
- transforms:
- - field: description
- expression: "{{ name.upper() }}[{{ status.value.lower() }}]"
-
- # Create the IPv4 and IPv6 from the InfraIXPConnection
- # /!\ 'address' is mandatory on Infrahub but it can be empty in PeeringManager
- - name: IpamIPAddress
- mapping: net/connections
- identifiers: ["address"]
- fields:
- - name: address
- mapping: ipv6_address
- - name: description
- mapping: name
- filters:
- - field: ipv6_address
- operation: "is_not_empty"
- - name: IpamIPAddress
- mapping: net/connections
- identifiers: ["address"]
- fields:
- - name: address
- mapping: ipv4_address
- - name: description
- mapping: name
- filters:
- - field: ipv4_address
- operation: "is_not_empty"
-
- - name: InfraIXPConnection
- mapping: net/connections
- identifiers: ["name"]
- fields:
- - name: name
- mapping: name
- - name: peeringdb_netixlan
- mapping: peeringdb_netixlan.id
- - name: description
- mapping: description
- - name: status
- mapping: status.value
- - name: vlan
- mapping: vlan
- - name: ipv6_address
- mapping: ipv6_address
- reference: IpamIPAddress
- - name: ipv4_address
- mapping: ipv4_address
- reference: IpamIPAddress
- - name: internet_exchange_point
- mapping: internet_exchange_point
- reference: InfraIXP
- # Showcase Filters
- # As we filter InfraIXP on the name S.H.I.E.L.D, we need to have the same filter here
- # to avoid importing IXP Connection without IXP
- filters:
- - field: internet_exchange_point.name
- operation: contains
- value: "S.H.I.E.L.D"
diff --git a/sync/examples/peering-manager_to_infrahub/infrahub/__init__.py b/sync/examples/peering-manager_to_infrahub/infrahub/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/sync/examples/peering-manager_to_infrahub/infrahub/sync_adapter.py b/sync/examples/peering-manager_to_infrahub/infrahub/sync_adapter.py
deleted file mode 100644
index e31f3f83d1..0000000000
--- a/sync/examples/peering-manager_to_infrahub/infrahub/sync_adapter.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from infrahub_sync.adapters.infrahub import InfrahubAdapter
-
-from .sync_models import (
- InfraAutonomousSystem,
- InfraBGPCommunity,
- InfraBGPPeerGroup,
- InfraBGPRoutingPolicy,
- InfraIXP,
- InfraIXPConnection,
- IpamIPAddress,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfrahubSync(InfrahubAdapter):
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraBGPPeerGroup = InfraBGPPeerGroup
- IpamIPAddress = IpamIPAddress
- InfraBGPRoutingPolicy = InfraBGPRoutingPolicy
- InfraBGPCommunity = InfraBGPCommunity
- InfraIXP = InfraIXP
- InfraIXPConnection = InfraIXPConnection
diff --git a/sync/examples/peering-manager_to_infrahub/infrahub/sync_models.py b/sync/examples/peering-manager_to_infrahub/infrahub/sync_models.py
deleted file mode 100644
index 7e87b8a69a..0000000000
--- a/sync/examples/peering-manager_to_infrahub/infrahub/sync_models.py
+++ /dev/null
@@ -1,120 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.infrahub import InfrahubModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfraAutonomousSystem(InfrahubModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("asn",)
- _attributes = ("name", "description", "irr_as_set", "ipv4_max_prefixes", "ipv6_max_prefixes", "affiliated")
- name: str
- asn: int
- description: Optional[str] = None
- irr_as_set: Optional[str] = None
- ipv4_max_prefixes: Optional[int] = None
- ipv6_max_prefixes: Optional[int] = None
- affiliated: Optional[bool] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPPeerGroup(InfrahubModel):
- _modelname = "InfraBGPPeerGroup"
- _identifiers = ("name",)
- _attributes = ("import_policies", "export_policies", "bgp_communities", "description", "status")
- name: str
- description: Optional[str] = None
- status: Optional[str] = None
- import_policies: Optional[List[str]] = []
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class IpamIPAddress(InfrahubModel):
- _modelname = "IpamIPAddress"
- _identifiers = ("address",)
- _attributes = ("description",)
- address: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPRoutingPolicy(InfrahubModel):
- _modelname = "InfraBGPRoutingPolicy"
- _identifiers = ("name",)
- _attributes = ("bgp_communities", "address_family", "label", "description", "policy_type", "weight")
- address_family: int
- label: Optional[str] = None
- description: Optional[str] = None
- name: str
- policy_type: str
- weight: Optional[int] = 1000
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPCommunity(InfrahubModel):
- _modelname = "InfraBGPCommunity"
- _identifiers = ("name",)
- _attributes = ("description", "value", "label", "community_type")
- description: Optional[str] = None
- name: str
- value: str
- label: Optional[str] = None
- community_type: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXP(InfrahubModel):
- _modelname = "InfraIXP"
- _identifiers = ("name",)
- _attributes = ("export_policies", "bgp_communities", "import_policies", "description", "status")
- description: Optional[str] = None
- name: str
- status: Optional[str] = "enabled"
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
- import_policies: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXPConnection(InfrahubModel):
- _modelname = "InfraIXPConnection"
- _identifiers = ("name",)
- _attributes = (
- "ipv4_address",
- "internet_exchange_point",
- "ipv6_address",
- "status",
- "vlan",
- "description",
- "peeringdb_netixlan",
- )
- status: Optional[str] = "enabled"
- vlan: Optional[int] = None
- name: str
- description: Optional[str] = None
- peeringdb_netixlan: Optional[int] = None
- ipv4_address: Optional[str] = None
- internet_exchange_point: str
- ipv6_address: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/examples/peering-manager_to_infrahub/peeringmanager/__init__.py b/sync/examples/peering-manager_to_infrahub/peeringmanager/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/sync/examples/peering-manager_to_infrahub/peeringmanager/sync_adapter.py b/sync/examples/peering-manager_to_infrahub/peeringmanager/sync_adapter.py
deleted file mode 100644
index 0717be8c98..0000000000
--- a/sync/examples/peering-manager_to_infrahub/peeringmanager/sync_adapter.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from infrahub_sync.adapters.peeringmanager import PeeringmanagerAdapter
-
-from .sync_models import (
- InfraAutonomousSystem,
- InfraBGPCommunity,
- InfraBGPPeerGroup,
- InfraBGPRoutingPolicy,
- InfraIXP,
- InfraIXPConnection,
- IpamIPAddress,
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class PeeringmanagerSync(PeeringmanagerAdapter):
- InfraAutonomousSystem = InfraAutonomousSystem
- InfraBGPPeerGroup = InfraBGPPeerGroup
- IpamIPAddress = IpamIPAddress
- InfraBGPRoutingPolicy = InfraBGPRoutingPolicy
- InfraBGPCommunity = InfraBGPCommunity
- InfraIXP = InfraIXP
- InfraIXPConnection = InfraIXPConnection
diff --git a/sync/examples/peering-manager_to_infrahub/peeringmanager/sync_models.py b/sync/examples/peering-manager_to_infrahub/peeringmanager/sync_models.py
deleted file mode 100644
index 42e59d24ca..0000000000
--- a/sync/examples/peering-manager_to_infrahub/peeringmanager/sync_models.py
+++ /dev/null
@@ -1,120 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.peeringmanager import PeeringmanagerModel
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class InfraAutonomousSystem(PeeringmanagerModel):
- _modelname = "InfraAutonomousSystem"
- _identifiers = ("asn",)
- _attributes = ("name", "description", "irr_as_set", "ipv4_max_prefixes", "ipv6_max_prefixes", "affiliated")
- name: str
- asn: int
- description: Optional[str] = None
- irr_as_set: Optional[str] = None
- ipv4_max_prefixes: Optional[int] = None
- ipv6_max_prefixes: Optional[int] = None
- affiliated: Optional[bool] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPPeerGroup(PeeringmanagerModel):
- _modelname = "InfraBGPPeerGroup"
- _identifiers = ("name",)
- _attributes = ("import_policies", "export_policies", "bgp_communities", "description", "status")
- name: str
- description: Optional[str] = None
- status: Optional[str] = None
- import_policies: Optional[List[str]] = []
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class IpamIPAddress(PeeringmanagerModel):
- _modelname = "IpamIPAddress"
- _identifiers = ("address",)
- _attributes = ("description",)
- address: str
- description: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPRoutingPolicy(PeeringmanagerModel):
- _modelname = "InfraBGPRoutingPolicy"
- _identifiers = ("name",)
- _attributes = ("bgp_communities", "address_family", "label", "description", "policy_type", "weight")
- address_family: int
- label: Optional[str] = None
- description: Optional[str] = None
- name: str
- policy_type: str
- weight: Optional[int] = 1000
- bgp_communities: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraBGPCommunity(PeeringmanagerModel):
- _modelname = "InfraBGPCommunity"
- _identifiers = ("name",)
- _attributes = ("description", "value", "label", "community_type")
- description: Optional[str] = None
- name: str
- value: str
- label: Optional[str] = None
- community_type: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXP(PeeringmanagerModel):
- _modelname = "InfraIXP"
- _identifiers = ("name",)
- _attributes = ("export_policies", "bgp_communities", "import_policies", "description", "status")
- description: Optional[str] = None
- name: str
- status: Optional[str] = "enabled"
- export_policies: Optional[List[str]] = []
- bgp_communities: Optional[List[str]] = []
- import_policies: Optional[List[str]] = []
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-
-
-class InfraIXPConnection(PeeringmanagerModel):
- _modelname = "InfraIXPConnection"
- _identifiers = ("name",)
- _attributes = (
- "ipv4_address",
- "internet_exchange_point",
- "ipv6_address",
- "status",
- "vlan",
- "description",
- "peeringdb_netixlan",
- )
- status: Optional[str] = "enabled"
- vlan: Optional[int] = None
- name: str
- description: Optional[str] = None
- peeringdb_netixlan: Optional[int] = None
- ipv4_address: Optional[str] = None
- internet_exchange_point: str
- ipv6_address: Optional[str] = None
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
diff --git a/sync/infrahub-sync/infrahub_sync/__init__.py b/sync/infrahub-sync/infrahub_sync/__init__.py
deleted file mode 100644
index e7198517b8..0000000000
--- a/sync/infrahub-sync/infrahub_sync/__init__.py
+++ /dev/null
@@ -1,202 +0,0 @@
-import operator
-import re
-from typing import Any, List, Optional, Union
-
-import pydantic
-from jinja2 import Template
-from netutils.ip import is_ip_within as netutils_is_ip_within
-
-from infrahub_sync.adapters.utils import get_value
-
-
-class SchemaMappingFilter(pydantic.BaseModel):
- field: str
- operation: str
- value: Optional[Any] = None
-
-
-class SchemaMappingTransform(pydantic.BaseModel):
- field: str
- expression: str
-
-
-class SchemaMappingField(pydantic.BaseModel):
- name: str
- mapping: Optional[str] = pydantic.Field(default=None)
- static: Optional[Any] = pydantic.Field(default=None)
- reference: Optional[str] = pydantic.Field(default=None)
-
-
-class SchemaMappingModel(pydantic.BaseModel):
- name: str
- mapping: str
- identifiers: Optional[List[str]] = pydantic.Field(default=None)
- filters: Optional[List[SchemaMappingFilter]] = pydantic.Field(default=None)
- transforms: Optional[List[SchemaMappingTransform]] = pydantic.Field(default=None)
- fields: List[SchemaMappingField] = []
-
-
-class SyncAdapter(pydantic.BaseModel):
- name: str
- settings: Optional[dict[str, Any]] = {}
-
-
-class SyncStore(pydantic.BaseModel):
- type: str
- settings: Optional[dict[str, Any]] = {}
-
-
-class SyncConfig(pydantic.BaseModel):
- name: str
- store: Optional[SyncStore] = []
- source: SyncAdapter
- destination: SyncAdapter
- order: List[str] = pydantic.Field(default_factory=list)
- schema_mapping: List[SchemaMappingModel] = []
-
-
-class SyncInstance(SyncConfig):
- directory: str
-
-
-def is_ip_within_filter(ip: str, ip_compare: Union[str, List[str]]) -> bool:
- """Check if an IP address is within a given subnet."""
- return netutils_is_ip_within(ip=ip, ip_compare=ip_compare)
-
-
-def convert_to_int(value: Any) -> int:
- try:
- return int(value)
- except (ValueError, TypeError) as exc:
- raise ValueError(f"Cannot convert '{value}' to int") from exc
-
-
-FILTERS_OPERATIONS = {
- "==": operator.eq,
- "!=": operator.ne,
- ">": lambda field, value: operator.gt(convert_to_int(field), convert_to_int(value)),
- "<": lambda field, value: operator.lt(convert_to_int(field), convert_to_int(value)),
- ">=": lambda field, value: operator.ge(convert_to_int(field), convert_to_int(value)),
- "<=": lambda field, value: operator.le(convert_to_int(field), convert_to_int(value)),
- "in": lambda field, value: value and field in value,
- "not in": lambda field, value: field not in value,
- "contains": lambda field, value: field and value in field,
- "not contains": lambda field, value: field and value not in field,
- "is_empty": lambda field: field is None or not field,
- "is_not_empty": lambda field: field is not None and field,
- "regex": lambda field, pattern: re.match(pattern, field) is not None,
- # Netutils
- "is_ip_within": lambda field, value: is_ip_within_filter(ip=field, ip_compare=value),
-}
-
-
-class DiffSyncMixin:
- def load(self):
- """Load all the models, one by one based on the order defined in top_level."""
- for item in self.top_level:
- if hasattr(self, f"load_{item}"):
- print(f"Loading {item}")
- method = getattr(self, f"load_{item}")
- method()
- else:
- print(f"Loading {item}")
- self.model_loader(model_name=item, model=getattr(self, item))
-
- def model_loader(self, model_name: str, model):
- raise NotImplementedError
-
-
-class DiffSyncModelMixin:
- @classmethod
- def apply_filter(cls, field_value: Any, operation: str, value: Any) -> bool:
- """Apply a specified operation to a field value."""
- operation_func = FILTERS_OPERATIONS.get(operation)
- if operation_func is None:
- raise ValueError(f"Unsupported operation: {operation}")
-
- # Handle is_empty and is_not_empty which do not use the value argument
- if operation in {"is_empty", "is_not_empty"}:
- return operation_func(field_value)
-
- return operation_func(field_value, value)
-
- @classmethod
- def apply_filters(cls, item: dict[str, Any], filters: List[SchemaMappingFilter]) -> bool:
- """Apply filters to an item and return True if it passes all filters."""
- for filter_obj in filters:
- # Use dot notation to access attributes
- field_value = get_value(obj=item, name=filter_obj.field)
- if not cls.apply_filter(field_value=field_value, operation=filter_obj.operation, value=filter_obj.value):
- return False
- return True
-
- @classmethod
- def apply_transform(cls, item: dict[str, Any], transform_expr: str, field: str) -> None:
- """Apply a transformation expression using Jinja2 to a specified field in the item."""
- try:
- # Create a Jinja2 template from the transformation expression
- template = Template(transform_expr)
-
- # Render the template using the item's context
- transformed_value = template.render(**item)
-
- # Assign the result back to the item
- item[field] = transformed_value
- except Exception as exc:
- raise ValueError(f"Failed to transform '{field}' with '{transform_expr}': {exc}") from exc
-
- @classmethod
- def apply_transforms(cls, item: dict[str, Any], transforms: List[SchemaMappingTransform]) -> dict[str, Any]:
- """Apply a list of structured transformations to an item."""
- for transform_obj in transforms:
- field = transform_obj.field
- expr = transform_obj.expression
- cls.apply_transform(item=item, transform_expr=expr, field=field)
- return item
-
- @classmethod
- def filter_records(cls, records: list[dict], schema_mapping: SchemaMappingModel) -> list[dict]:
- """
- Apply filters to the records based on the schema mapping configuration.
- """
- filters = schema_mapping.filters or []
- if not filters:
- return records
- filtered_records = []
- for record in records:
- if cls.apply_filters(item=record, filters=filters):
- filtered_records.append(record)
- return filtered_records
-
- @classmethod
- def transform_records(cls, records: list[dict], schema_mapping: SchemaMappingModel) -> list[dict]:
- """
- Apply transformations to the records based on the schema mapping configuration.
- """
- transforms = schema_mapping.transforms or []
- if not transforms:
- return records
- transformed_records = []
- for record in records:
- transformed_record = cls.apply_transforms(item=record, transforms=transforms)
- transformed_records.append(transformed_record)
- return transformed_records
-
- @classmethod
- def get_resource_name(cls, schema_mapping: List[SchemaMappingModel]) -> str:
- """Get the resource name from the schema mapping."""
- for element in schema_mapping:
- if element.name == cls.__name__:
- return element.mapping
- raise ValueError(f"Resource name not found for class {cls.__name__}")
-
- @classmethod
- def is_list(cls, name):
- field = cls.__fields__.get(name)
- if not field:
- raise ValueError(f"Unable to find the field {name} under {cls}")
-
- if isinstance(field.default, list):
- return True
-
- return False
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/infrahub.py b/sync/infrahub-sync/infrahub_sync/adapters/infrahub.py
deleted file mode 100644
index 647c212aed..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/infrahub.py
+++ /dev/null
@@ -1,247 +0,0 @@
-import copy
-import os
-from typing import Any, Mapping
-
-from infrahub_sdk import (
- Config,
- InfrahubClientSync,
- InfrahubNodeSync,
- NodeSchema,
- NodeStoreSync,
-)
-from infrahub_sdk.exceptions import NodeNotFoundError
-from infrahub_sdk.utils import compare_lists
-
-from diffsync import Adapter, DiffSyncModel
-from infrahub_sync import (
- DiffSyncMixin,
- DiffSyncModelMixin,
- SyncAdapter,
- SyncConfig,
-)
-from infrahub_sync.generator import has_field
-
-
-def update_node(node: InfrahubNodeSync, attrs: dict):
- for attr_name, attr_value in attrs.items():
- if attr_name in node._schema.attribute_names:
- attr = getattr(node, attr_name)
- attr.value = attr_value
-
- if attr_name in node._schema.relationship_names:
- for rel_schema in node._schema.relationships:
- if attr_name == rel_schema.name and rel_schema.cardinality == "one":
- if attr_value:
- if rel_schema.kind != "Generic":
- peer = node._client.store.get(
- key=attr_value, kind=rel_schema.peer, raise_when_missing=False
- )
- else:
- peer = node._client.store.get(key=attr_value, raise_when_missing=False)
- if not peer:
- print(f"Unable to find {rel_schema.peer} [{attr_value}] in the Store - Ignored")
- continue
- setattr(node, attr_name, peer)
- else:
- # TODO: Do we want to delete old relationship here ?
- pass
-
- if attr_name == rel_schema.name and rel_schema.cardinality == "many":
- attr = getattr(node, attr_name)
- existing_peer_ids = attr.peer_ids
- new_peer_ids = [
- node._client.store.get(key=value, kind=rel_schema.peer).id for value in list(attr_value)
- ]
- _, existing_only, new_only = compare_lists(existing_peer_ids, new_peer_ids) # noqa: F841
-
- for existing_id in existing_only:
- attr.remove(existing_id)
-
- for new_id in new_only:
- attr.add(new_id)
-
- return node
-
-
-def diffsync_to_infrahub(ids: Mapping[Any, Any], attrs: Mapping[Any, Any], store: NodeStoreSync, schema: NodeSchema):
- data = copy.deepcopy(dict(ids))
- data.update(dict(attrs))
-
- for key in list(data.keys()):
- if key in schema.relationship_names:
- for rel_schema in schema.relationships:
- if key == rel_schema.name and rel_schema.cardinality == "one":
- if data[key] is None:
- del data[key]
- continue
- if rel_schema.kind != "Generic":
- peer = store.get(key=data[key], kind=rel_schema.peer, raise_when_missing=False)
- else:
- peer = store.get(key=data[key], raise_when_missing=False)
- if not peer:
- print(f"Unable to find {rel_schema.peer} [{data[key]}] in the Store - Ignored")
- continue
-
- data[key] = peer.id
- if key == rel_schema.name and rel_schema.cardinality == "many":
- if data[key] is None:
- del data[key]
- continue
- new_values = [store.get(key=value, kind=rel_schema.peer).id for value in list(data[key])]
- data[key] = new_values
-
- return data
-
-
-class InfrahubAdapter(DiffSyncMixin, Adapter):
- type = "Infrahub"
-
- def __init__(self, *args, target: str, adapter: SyncAdapter, config: SyncConfig, branch: str = None, **kwargs):
- super().__init__(*args, **kwargs)
- self.target = target
- self.config = config
-
- settings = adapter.settings or {}
- url = os.environ.get("INFRAHUB_ADDRESS") or os.environ.get("INFRAHUB_URL") or settings.get("url")
- token = os.environ.get("INFRAHUB_API_TOKEN") or settings.get("token")
-
- if not url or not token:
- raise ValueError("Both url and token must be specified!")
-
- if branch:
- sdk_config = Config(timeout=60, default_branch=branch, api_token=token)
- else:
- sdk_config = Config(timeout=60, api_token=token)
-
- self.client = InfrahubClientSync(address=url, config=sdk_config)
-
- # We need to identify with an account until we have some auth in place
- remote_account = config.source.name
- try:
- self.account = self.client.get(kind="CoreAccount", name__value=remote_account)
- except NodeNotFoundError:
- self.account = None
-
- def model_loader(self, model_name: str, model: "InfrahubModel"):
- """
- Load and process models using schema mapping filters and transformations.
-
- This method retrieves data from Infrahub, applies filters and transformations
- as specified in the schema mapping, and loads the processed data into the adapter.
- """
- element = next((el for el in self.config.schema_mapping if el.name == model_name), None)
- if element:
- # Retrieve all nodes corresponding to model_name (list of InfrahubNodeSync)
- nodes = self.client.all(kind=model_name, populate_store=True)
-
- # Transform the list of InfrahubNodeSync into a list of (node, dict) tuples
- node_dict_pairs = [(node, self.infrahub_node_to_diffsync(node=node)) for node in nodes]
- total = len(node_dict_pairs)
-
- # Extract the list of dicts for filtering and transforming
- list_obj = [pair[1] for pair in node_dict_pairs]
-
- if self.config.source.name.title() == self.type.title():
- # Filter records
- filtered_objs = model.filter_records(records=list_obj, schema_mapping=element)
- print(f"{self.type}: Loading {len(filtered_objs)}/{total} {model_name}")
- # Transform records
- transformed_objs = model.transform_records(records=filtered_objs, schema_mapping=element)
- else:
- print(f"{self.type}: Loading all {total} {model_name}")
- transformed_objs = list_obj
-
- # Create model instances after filtering and transforming
- for transformed_obj in transformed_objs:
- original_node = next(node for node, obj in node_dict_pairs if obj == transformed_obj)
- item = model(**transformed_obj)
- unique_id = item.get_unique_id()
- self.client.store.set(key=unique_id, node=original_node)
- self.update_or_add_model_instance(item)
-
- def infrahub_node_to_diffsync(self, node: InfrahubNodeSync) -> dict:
- """Convert an InfrahubNode into a dict that will be used to create a DiffSyncModel."""
- data: dict[str, Any] = {"local_id": str(node.id)}
-
- for attr_name in node._schema.attribute_names:
- if has_field(config=self.config, name=node._schema.kind, field=attr_name):
- attr = getattr(node, attr_name)
- # Is it the right place to do it or are we missing some de-serialize ?
- # got a ValidationError from pydantic while trying to get the model(**data)
- # for IPHost and IPInterface
- if attr.value and not isinstance(attr.value, str):
- data[attr_name] = str(attr.value)
- else:
- data[attr_name] = attr.value
-
- for rel_schema in node._schema.relationships:
- if not has_field(config=self.config, name=node._schema.kind, field=rel_schema.name):
- continue
- if rel_schema.cardinality == "one":
- rel = getattr(node, rel_schema.name)
- if not rel.id:
- continue
- if rel_schema.kind != "Generic":
- peer_node = self.client.store.get(key=rel.id, kind=rel_schema.peer, raise_when_missing=False)
- else:
- peer_node = self.client.store.get(key=rel.id, raise_when_missing=False)
- if not peer_node:
- # I am not sure if we should end up here "normaly"
- print(f"Debug Unable to find {rel_schema.peer} [{rel.id}] in the Store - Pulling from Infrahub")
- peer_node = self.client.get(id=rel.id, kind=rel_schema.peer, populate_store=True)
- if not peer_node:
- print(f"Unable to find {rel_schema.peer} [{rel.id}]")
- continue
-
- peer_data = self.infrahub_node_to_diffsync(node=peer_node)
- peer_kind = f"{peer_node._schema.namespace}{peer_node._schema.name}"
- peer_model = getattr(self, peer_kind)
- peer_item = peer_model(**peer_data)
-
- data[rel_schema.name] = peer_item.get_unique_id()
-
- elif rel_schema.cardinality == "many":
- values = []
- rel_manager = getattr(node, rel_schema.name)
- for peer in rel_manager:
- peer_node = self.client.store.get(key=peer.id, kind=rel_schema.peer)
- peer_data = self.infrahub_node_to_diffsync(node=peer_node)
- peer_model = getattr(self, rel_schema.peer)
- peer_item = peer_model(**peer_data)
-
- values.append(peer_item.get_unique_id())
-
- data[rel_schema.name] = values
-
- return data
-
-
-class InfrahubModel(DiffSyncModelMixin, DiffSyncModel):
- @classmethod
- def create(
- cls,
- adapter: Adapter,
- ids: Mapping[Any, Any],
- attrs: Mapping[Any, Any],
- ):
- schema = adapter.client.schema.get(kind=cls.__name__)
- data = diffsync_to_infrahub(ids=ids, attrs=attrs, schema=schema, store=adapter.client.store)
- unique_id = cls(**ids, **attrs).get_unique_id()
- source_id = None
- if adapter.account:
- source_id = adapter.account.id
- create_data = adapter.client.schema.generate_payload_create(
- schema=schema, data=data, source=source_id, is_protected=True
- )
- node = adapter.client.create(kind=cls.__name__, data=create_data)
- node.save(allow_upsert=True)
- adapter.client.store.set(key=unique_id, node=node)
-
- return super().create(adapter=adapter, ids=ids, attrs=attrs)
-
- def update(self, attrs):
- node = self.adapter.client.get(id=self.local_id, kind=self.__class__.__name__)
- node = update_node(node=node, attrs=attrs)
- node.save(allow_upsert=True)
-
- return super().update(attrs)
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/ipfabricsync.py b/sync/infrahub-sync/infrahub_sync/adapters/ipfabricsync.py
deleted file mode 100644
index 507d3671f5..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/ipfabricsync.py
+++ /dev/null
@@ -1,146 +0,0 @@
-from __future__ import annotations
-
-from typing import Any, Mapping
-
-try:
- from ipfabric import IPFClient
-except ImportError as e:
- print(e)
-
-from diffsync import Adapter, DiffSyncModel
-from infrahub_sync import (
- DiffSyncMixin,
- DiffSyncModelMixin,
- SchemaMappingModel,
- SyncAdapter,
- SyncConfig,
-)
-
-ipf_filters = {
- "tables/inventory/summary/platforms": {"and": [{"platform": ["empty", False]}]},
- "tables/inventory/summary/models": {"and": [{"model": ["empty", False]}]},
- "tables/inventory/pn": {"and": [{"name": ["empty", False]}]},
-}
-
-
-class IpfabricsyncAdapter(DiffSyncMixin, Adapter):
- type = "IPFabric"
-
- def __init__(self, *args, target: str, adapter: SyncAdapter, config: SyncConfig, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.target = target
- self.client = self._create_ipfabric_client(adapter)
- self.config = config
-
- def _create_ipfabric_client(self, adapter: SyncAdapter):
- settings = adapter.settings or {}
-
- base_url = settings.get("base_url") or None
- auth = settings.get("auth") or None
-
- if not base_url or not auth:
- raise ValueError("Both url and auth must be specified!")
-
- return IPFClient(**settings)
-
- def build_mapping(self, reference, obj):
- # Get object class and model name from the store
- object_class, modelname = self.store._get_object_class_and_model(model=reference)
-
- # Find the schema element matching the model name
- schema_element = next((element for element in self.config.schema_mapping if element.name == modelname), None)
-
- # Collect all relevant field mappings for identifiers
- new_identifiers = []
-
- # Convert schema_element.fields to a dictionary for fast lookup
- field_dict = {field.name: field.mapping for field in schema_element.fields}
-
- # Loop through object_class._identifiers to find corresponding field mappings
- for identifier in object_class._identifiers:
- if identifier in field_dict:
- new_identifiers.append(field_dict[identifier])
-
- # Construct the unique identifier, using a fallback if a key isn't found
- unique_id = "__".join(str(obj.get(key, "")) for key in new_identifiers)
- return unique_id
-
- def model_loader(self, model_name, model):
- """
- Load and process models using schema mapping filters and transformations.
-
- This method retrieves data from IP Fabric, and loads the processed data into the adapter.
- """
- for element in self.config.schema_mapping:
- if not element.name == model_name:
- continue
-
- table = self.client.fetch_all(element.mapping, filters=ipf_filters.get(element.mapping))
- print(f"{self.type}: Loading {len(table)} from `{element.mapping}`")
-
- # TODO Filter records
- # TODO Transform records
- for obj in table:
- data = self.ipfabric_dict_to_diffsync(obj=obj, mapping=element, model=model)
- item = model(**data)
- self.update_or_add_model_instance(item)
-
- def ipfabric_dict_to_diffsync(self, obj: dict, mapping: SchemaMappingModel, model: IpfabricsyncModel) -> dict: # pylint: disable=too-many-branches
- data: dict[str, Any] = {"local_id": str(obj["id"])}
-
- for field in mapping.fields: # pylint: disable=too-many-nested-blocks
- field_is_list = model.is_list(name=field.name)
-
- if field.static:
- data[field.name] = field.static
- elif not field_is_list and field.mapping and not field.reference:
- value = obj.get(field.mapping)
- if value is not None:
- # TODO: Be able to do this in the infrahub-sync mapping file
- if field.name == "speed":
- data[field.name] = value / 1000
- else:
- data[field.name] = value
- elif field_is_list and field.mapping and not field.reference:
- raise NotImplementedError(
- "it's not supported yet to have an attribute of type list with a simple mapping"
- )
-
- elif field.mapping and field.reference:
- all_nodes_for_reference = self.store.get_all(model=field.reference)
-
- nodes = [item for item in all_nodes_for_reference] # noqa: C416
- if not nodes and all_nodes_for_reference:
- raise IndexError(
- f"Unable to get '{field.mapping}' with '{field.reference}' reference from store."
- f" The available models are {self.store.get_all_model_names()}"
- )
- if not field_is_list:
- if node := obj[field.mapping]:
- matching_nodes = []
- node_id = self.build_mapping(reference=field.reference, obj=obj)
- matching_nodes = [item for item in nodes if str(item) == node_id]
- if len(matching_nodes) == 0:
- data[field.name] = None
- else:
- node = matching_nodes[0]
- data[field.name] = node.get_unique_id()
-
- return data
-
-
-class IpfabricsyncModel(DiffSyncModelMixin, DiffSyncModel):
- @classmethod
- def create(
- cls,
- adapter: Adapter,
- ids: Mapping[Any, Any],
- attrs: Mapping[Any, Any],
- ):
- # TODO
- return super().create(adapter=adapter, ids=ids, attrs=attrs)
-
- def update(self, attrs):
- # TODO
- return super().update(attrs)
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/librenms.py b/sync/infrahub-sync/infrahub_sync/adapters/librenms.py
deleted file mode 100644
index ea249f7479..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/librenms.py
+++ /dev/null
@@ -1,158 +0,0 @@
-from __future__ import annotations
-
-import os
-from typing import Any, Mapping
-
-from diffsync import Adapter, DiffSyncModel
-from infrahub_sync import (
- DiffSyncMixin,
- DiffSyncModelMixin,
- SchemaMappingModel,
- SyncAdapter,
- SyncConfig,
-)
-
-from .rest_api_client import RestApiClient
-from .utils import derive_identifier_key, get_value
-
-
-class LibrenmsAdapter(DiffSyncMixin, Adapter):
- type = "LibreNMS"
-
- def __init__(self, *args, target: str, adapter: SyncAdapter, config: SyncConfig, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.target = target
- self.client = self._create_rest_client(adapter)
- self.config = config
-
- def _create_rest_client(self, adapter: SyncAdapter) -> RestApiClient:
- settings = adapter.settings or {}
- url = os.environ.get("LIBRENMS_ADDRESS") or os.environ.get("LIBRENMS_URL") or settings.get("url")
- api_endpoint = settings.get("api_endpoint", "/api/v0")
- auth_method = settings.get("auth_method", "x-auth-token")
- api_token = os.environ.get("LIBRENMS_TOKEN") or settings.get("token")
- timeout = settings.get("timeout", 30)
-
- if not url:
- raise ValueError("url must be specified!")
-
- if auth_method != "x-auth-token" or not api_token:
- raise ValueError("Token-based authentication requires a valid API token!")
-
- full_base_url = f"{url.rstrip('/')}/{api_endpoint.strip('/')}"
- return RestApiClient(base_url=full_base_url, auth_method=auth_method, api_token=api_token, timeout=timeout)
-
- def model_loader(self, model_name: str, model: LibrenmsModel):
- """
- Load and process models using schema mapping filters and transformations.
-
- This method retrieves data from Librenms, applies filters and transformations
- as specified in the schema mapping, and loads the processed data into the adapter.
- """
- for element in self.config.schema_mapping:
- if not element.name == model_name:
- continue
-
- # Use the resource endpoint from the schema mapping
- resource_name = element.mapping
- response_key = resource_name.split("/")[-1]
-
- try:
- # Fetch data from the specified resource endpoint
- response_data = self.client.get(resource_name)
- objs = response_data.get(response_key, [])
- except Exception as exc:
- raise ValueError(f"Error fetching data from REST API: {str(exc)}") from exc
-
- total = len(objs)
- if self.config.source.name.title() == self.type.title():
- # Filter records
- filtered_objs = model.filter_records(records=objs, schema_mapping=element)
- print(f"{self.type}: Loading {len(filtered_objs)}/{total} {resource_name}")
- # Transform records
- transformed_objs = model.transform_records(records=filtered_objs, schema_mapping=element)
- else:
- print(f"{self.type}: Loading all {total} {resource_name}")
- transformed_objs = objs
-
- # Create model instances after filtering and transforming
- for obj in transformed_objs:
- data = self.obj_to_diffsync(obj=obj, mapping=element, model=model)
- item = model(**data)
- self.add(item)
-
- def obj_to_diffsync(self, obj: dict[str, Any], mapping: SchemaMappingModel, model: LibrenmsModel) -> dict: # noqa: C901
- obj_id = derive_identifier_key(obj=obj)
- data: dict[str, Any] = {"local_id": str(obj_id)}
-
- for field in mapping.fields: # pylint: disable=too-many-nested-blocks
- field_is_list = model.is_list(name=field.name)
-
- if field.static:
- data[field.name] = field.static
- elif not field_is_list and field.mapping and not field.reference:
- value = get_value(obj, field.mapping)
- if value is not None:
- data[field.name] = value
- elif field_is_list and field.mapping and not field.reference:
- raise NotImplementedError(
- "it's not supported yet to have an attribute of type list with a simple mapping"
- )
-
- elif field.mapping and field.reference:
- all_nodes_for_reference = self.store.get_all(model=field.reference)
- nodes = [item for item in all_nodes_for_reference] # noqa: C416
- if not nodes and all_nodes_for_reference:
- raise IndexError(
- f"Unable to get '{field.mapping}' with '{field.reference}' reference from store."
- f" The available models are {self.store.get_all_model_names()}"
- )
- if not field_is_list:
- if node := get_value(obj, field.mapping):
- if isinstance(node, dict):
- matching_nodes = []
- node_id = node.get("id", None)
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {model} {node_id}")
- node = matching_nodes[0]
- data[field.name] = node.get_unique_id()
- else:
- # Some link are referencing the node identifier directly without the id (i.e location in device)
- data[field.name] = node
-
- else:
- data[field.name] = []
- for node in get_value(obj, field.mapping):
- if not node:
- continue
- node_id = node.get("id", None)
- if not node_id:
- if isinstance(node, tuple):
- node_id = node[1] if node[0] == "id" else None
- if not node_id:
- continue
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {field.reference} {node_id}")
- data[field.name].append(matching_nodes[0].get_unique_id())
- data[field.name] = sorted(data[field.name])
-
- return data
-
-
-class LibrenmsModel(DiffSyncModelMixin, DiffSyncModel):
- @classmethod
- def create(
- cls,
- adapter: Adapter,
- ids: Mapping[Any, Any],
- attrs: Mapping[Any, Any],
- ):
- # TODO
- return super().create(adapter=adapter, ids=ids, attrs=attrs)
-
- def update(self, attrs):
- # TODO
- return super().update(attrs)
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/nautobot.py b/sync/infrahub-sync/infrahub_sync/adapters/nautobot.py
deleted file mode 100644
index 3a59b95847..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/nautobot.py
+++ /dev/null
@@ -1,159 +0,0 @@
-from __future__ import annotations
-
-# pylint: disable=R0801
-import os
-from typing import Any, Mapping
-
-import pynautobot
-
-from diffsync import Adapter, DiffSyncModel
-from infrahub_sync import (
- DiffSyncMixin,
- DiffSyncModelMixin,
- SchemaMappingModel,
- SyncAdapter,
- SyncConfig,
-)
-
-from .utils import get_value
-
-
-class NautobotAdapter(DiffSyncMixin, Adapter):
- type = "Nautobot"
-
- def __init__(self, *args, target: str, adapter: SyncAdapter, config: SyncConfig, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.target = target
- self.client = self._create_nautobot_client(adapter)
- self.config = config
-
- def _create_nautobot_client(self, adapter: SyncAdapter):
- settings = adapter.settings or {}
- url = os.environ.get("NAUTOBOT_ADDRESS") or os.environ.get("NAUTOBOT_URL") or settings.get("url")
- token = os.environ.get("NAUTOBOT_TOKEN") or settings.get("token")
-
- if not url or not token:
- raise ValueError("Both url and token must be specified!")
-
- return pynautobot.api(url, token=token, threading=True, max_workers=5, retries=3)
-
- def model_loader(self, model_name: str, model: NautobotModel):
- """
- Load and process models using schema mapping filters and transformations.
-
- This method retrieves data from Nautobot, applies filters and transformations
- as specified in the schema mapping, and loads the processed data into the adapter.
- """
- # Retrieve schema mapping for this model
- for element in self.config.schema_mapping:
- if not element.name == model_name:
- continue
-
- # Use the resource endpoint from the schema mapping
- app_name, resource_name = element.mapping.split(".")
- nautobot_app = getattr(self.client, app_name)
- nautobot_model = getattr(nautobot_app, resource_name)
-
- # Retrieve all objects (RecordSet)
- nodes = nautobot_model.all()
-
- # Transform the RecordSet into a list of Dict
- list_obj = []
- for node in nodes:
- list_obj.append(dict(node))
-
- total = len(list_obj)
- if self.config.source.name.title() == self.type.title():
- # Filter records
- filtered_objs = model.filter_records(records=list_obj, schema_mapping=element)
- print(f"{self.type}: Loading {len(filtered_objs)}/{total} {resource_name}")
- # Transform records
- transformed_objs = model.transform_records(records=filtered_objs, schema_mapping=element)
- else:
- print(f"{self.type}: Loading all {total} {resource_name}")
- transformed_objs = list_obj
-
- # Create model instances after filtering and transforming
- for obj in transformed_objs:
- data = self.nautobot_obj_to_diffsync(obj=obj, mapping=element, model=model)
- item = model(**data)
- self.add(item)
-
- def nautobot_obj_to_diffsync(self, obj: dict[str, Any], mapping: SchemaMappingModel, model: NautobotModel) -> dict: # noqa: C901
- obj_id = obj.get("id", None)
- data: dict[str, Any] = {"local_id": str(obj_id)}
-
- for field in mapping.fields: # pylint: disable=too-many-nested-blocks
- field_is_list = model.is_list(name=field.name)
-
- if field.static:
- data[field.name] = field.static
- elif not field_is_list and field.mapping and not field.reference:
- value = get_value(obj, field.mapping)
- if value is not None:
- data[field.name] = value
- elif field_is_list and field.mapping and not field.reference:
- raise NotImplementedError(
- "it's not supported yet to have an attribute of type list with a simple mapping"
- )
-
- elif field.mapping and field.reference:
- all_nodes_for_reference = self.store.get_all(model=field.reference)
- nodes = [item for item in all_nodes_for_reference] # noqa: C416
- if not nodes and all_nodes_for_reference:
- raise IndexError(
- f"Unable to get '{field.mapping}' with '{field.reference}' reference from store."
- f" The available models are {self.store.get_all_model_names()}"
- )
- if not field_is_list:
- if node := get_value(obj, field.mapping):
- matching_nodes = []
- node_id = node.get("id", None)
- if node_id:
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- # If the peer is a Node we are filtering, we could end up not finding it
- # raise IndexError(f"Unable to locate the node {field.name} {node_id}")
- print(f"Unable to locate the node {field.name} {node_id}")
- continue
- node = matching_nodes[0]
- data[field.name] = node.get_unique_id()
-
- else:
- data[field.name] = []
- for node in get_value(obj, field.mapping):
- if not node:
- continue
- node_id = node.get("id", None)
- if not node_id:
- if isinstance(node, tuple):
- node_id = node[1] if node[0] == "id" else None
- if not node_id:
- continue
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- # If the peer is a Node we are filtering, we could end up not finding it
- # raise IndexError(f"Unable to locate the node {field.name} {node_id}")
- print(f"Unable to locate the node {field.name} {node_id}")
- continue
- data[field.name].append(matching_nodes[0].get_unique_id())
- data[field.name] = sorted(data[field.name])
-
- return data
-
-
-class NautobotModel(DiffSyncModelMixin, DiffSyncModel):
- @classmethod
- def create(
- cls,
- adapter: Adapter,
- ids: Mapping[Any, Any],
- attrs: Mapping[Any, Any],
- ):
- # TODO
- return super().create(adapter=adapter, ids=ids, attrs=attrs)
-
- def update(self, attrs):
- # TODO
- return super().update(attrs)
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/netbox.py b/sync/infrahub-sync/infrahub_sync/adapters/netbox.py
deleted file mode 100644
index 7cc975fd76..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/netbox.py
+++ /dev/null
@@ -1,152 +0,0 @@
-from __future__ import annotations
-
-# pylint: disable=R0801
-import os
-from typing import Any, Mapping
-
-import pynetbox
-
-from diffsync import Adapter, DiffSyncModel
-from infrahub_sync import (
- DiffSyncMixin,
- DiffSyncModelMixin,
- SchemaMappingModel,
- SyncAdapter,
- SyncConfig,
-)
-
-from .utils import get_value
-
-
-class NetboxAdapter(DiffSyncMixin, Adapter):
- type = "Netbox"
-
- def __init__(self, *args, target: str, adapter: SyncAdapter, config: SyncConfig, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.target = target
- self.client = self._create_netbox_client(adapter)
- self.config = config
-
- def _create_netbox_client(self, adapter: SyncAdapter):
- settings = adapter.settings or {}
- url = os.environ.get("NETBOX_ADDRESS") or os.environ.get("NETBOX_URL") or settings.get("url")
- token = os.environ.get("NETBOX_TOKEN") or settings.get("token")
-
- if not url or not token:
- raise ValueError("Both url and token must be specified!")
-
- return pynetbox.api(url, token=token)
-
- def model_loader(self, model_name: str, model: NetboxModel):
- """
- Load and process models using schema mapping filters and transformations.
-
- This method retrieves data from Netbox, applies filters and transformations
- as specified in the schema mapping, and loads the processed data into the adapter.
- """
- for element in self.config.schema_mapping:
- if not element.name == model_name:
- continue
-
- # Use the resource endpoint from the schema mapping
- app_name, resource_name = element.mapping.split(".")
- netbox_app = getattr(self.client, app_name)
- netbox_model = getattr(netbox_app, resource_name)
-
- # Retrieve all objects (RecordSet)
- nodes = netbox_model.all()
-
- # Transform the RecordSet into a list of Dict
- list_obj = []
- for node in nodes:
- list_obj.append(dict(node))
-
- total = len(list_obj)
- if self.config.source.name.title() == self.type.title():
- # Filter records
- filtered_objs = model.filter_records(records=list_obj, schema_mapping=element)
- print(f"{self.type}: Loading {len(filtered_objs)}/{total} {resource_name}")
- # Transform records
- transformed_objs = model.transform_records(records=filtered_objs, schema_mapping=element)
- else:
- print(f"{self.type}: Loading all {total} {resource_name}")
- transformed_objs = list_obj
-
- # Create model instances after filtering and transforming
- for obj in transformed_objs:
- data = self.netbox_obj_to_diffsync(obj=obj, mapping=element, model=model)
- item = model(**data)
- self.add(item)
-
- def netbox_obj_to_diffsync(self, obj: dict[str, Any], mapping: SchemaMappingModel, model: NetboxModel) -> dict: # noqa: C901
- obj_id = obj.get("id", None)
- data: dict[str, Any] = {"local_id": str(obj_id)}
-
- for field in mapping.fields: # pylint: disable=too-many-nested-blocks
- field_is_list = model.is_list(name=field.name)
-
- if field.static:
- data[field.name] = field.static
- elif not field_is_list and field.mapping and not field.reference:
- value = get_value(obj, field.mapping)
- if value is not None:
- data[field.name] = value
- elif field_is_list and field.mapping and not field.reference:
- raise NotImplementedError(
- "It's not supported yet to have an attribute of type list with a simple mapping"
- )
- elif field.mapping and field.reference:
- all_nodes_for_reference = self.store.get_all(model=field.reference)
- nodes = [item for item in all_nodes_for_reference]
- if not nodes and all_nodes_for_reference:
- raise IndexError(
- f"Unable to get '{field.mapping}' with '{field.reference}' reference from store."
- f" The available models are {self.store.get_all_model_names()}"
- )
- if not field_is_list:
- if node := get_value(obj, field.mapping):
- if isinstance(node, dict):
- matching_nodes = []
- node_id = node.get("id", None)
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {field.name} {node_id}")
- node = matching_nodes[0]
- data[field.name] = node.get_unique_id()
- else:
- data[field.name] = node
- else:
- data[field.name] = []
- for node in get_value(obj, field.mapping):
- if not node:
- continue
- node_id = node.get("id", None)
- if not node_id:
- if isinstance(node, tuple):
- node_id = node[1] if node[0] == "id" else None
- if not node_id:
- continue
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {field.reference} {node_id}")
- data[field.name].append(matching_nodes[0].get_unique_id())
- data[field.name] = sorted(data[field.name])
-
- return data
-
-
-class NetboxModel(DiffSyncModelMixin, DiffSyncModel):
- @classmethod
- def create(
- cls,
- adapter: Adapter,
- ids: Mapping[Any, Any],
- attrs: Mapping[Any, Any],
- ):
- # TODO
- return super().create(adapter=adapter, ids=ids, attrs=attrs)
-
- def update(self, attrs):
- # TODO
- return super().update(attrs)
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/observium.py b/sync/infrahub-sync/infrahub_sync/adapters/observium.py
deleted file mode 100644
index 09cdc4149a..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/observium.py
+++ /dev/null
@@ -1,166 +0,0 @@
-from __future__ import annotations
-
-import os
-from typing import Any, Mapping
-
-from diffsync import Adapter, DiffSyncModel
-from infrahub_sync import (
- DiffSyncMixin,
- DiffSyncModelMixin,
- SchemaMappingModel,
- SyncAdapter,
- SyncConfig,
-)
-
-from .rest_api_client import RestApiClient
-from .utils import derive_identifier_key, get_value
-
-
-class ObserviumAdapter(DiffSyncMixin, Adapter):
- type = "Observium"
-
- def __init__(self, *args, target: str, adapter: SyncAdapter, config: SyncConfig, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.target = target
- self.client = self._create_rest_client(adapter)
- self.config = config
-
- def _create_rest_client(self, adapter: SyncAdapter) -> RestApiClient:
- settings = adapter.settings or {}
- url = os.environ.get("OBSERVIUM_ADDRESS") or os.environ.get("OBSERVIUM_URL") or settings.get("url")
- api_endpoint = settings.get("api_endpoint", "/api/v0")
- auth_method = settings.get("auth_method", "basic")
- api_token = os.environ.get("OBSERVIUM_TOKEN") or settings.get("token")
- username = os.environ.get("OBSERVIUM_USERNAME") or settings.get("username")
- password = os.environ.get("OBSERVIUM_PASSWORD") or settings.get("password")
- timeout = settings.get("timeout")
-
- if not url:
- raise ValueError("url must be specified!")
-
- base_url = f"{url.rstrip('/')}/{api_endpoint.strip('/')}"
- return RestApiClient(
- base_url=base_url,
- auth_method=auth_method,
- api_token=api_token,
- username=username,
- password=password,
- timeout=timeout,
- )
-
- def model_loader(self, model_name: str, model: ObserviumModel):
- """
- Load and process models using schema mapping filters and transformations.
-
- This method retrieves data from Observium, applies filters and transformations
- as specified in the schema mapping, and loads the processed data into the adapter.
- """
- for element in self.config.schema_mapping:
- if not element.name == model_name:
- continue
-
- # Use the resource endpoint from the schema mapping
- resource_name = element.mapping
-
- try:
- # Fetch data from the specified resource endpoint
- response_data = self.client.get(resource_name)
- objs = response_data.get(resource_name, {})
- except Exception as exc:
- raise ValueError(f"Error fetching data from REST API: {str(exc)}") from exc
-
- if isinstance(objs, dict):
- objs = list(objs.values())
-
- total = len(objs)
- if self.config.source.name.title() == self.type.title():
- # Filter records
- filtered_objs = model.filter_records(records=objs, schema_mapping=element)
- print(f"{self.type}: Loading {len(filtered_objs)}/{total} {resource_name}")
- # Transform records
- transformed_objs = model.transform_records(records=filtered_objs, schema_mapping=element)
- else:
- print(f"{self.type}: Loading all {total} {resource_name}")
- transformed_objs = objs
-
- # Create model instances after filtering and transforming
- for obj in transformed_objs:
- data = self.obj_to_diffsync(obj=obj, mapping=element, model=model)
- item = model(**data)
- self.add(item)
-
- def obj_to_diffsync(self, obj: dict[str, Any], mapping: SchemaMappingModel, model: ObserviumModel) -> dict: # noqa: C901
- obj_id = derive_identifier_key(obj=obj)
- data: dict[str, Any] = {"local_id": str(obj_id)}
-
- for field in mapping.fields: # pylint: disable=too-many-nested-blocks
- field_is_list = model.is_list(name=field.name)
-
- if field.static:
- data[field.name] = field.static
- elif not field_is_list and field.mapping and not field.reference:
- value = get_value(obj, field.mapping)
- if value is not None:
- data[field.name] = value
- elif field_is_list and field.mapping and not field.reference:
- raise NotImplementedError(
- "it's not supported yet to have an attribute of type list with a simple mapping"
- )
-
- elif field.mapping and field.reference:
- all_nodes_for_reference = self.store.get_all(model=field.reference)
- nodes = [item for item in all_nodes_for_reference] # noqa: C416
- if not nodes and all_nodes_for_reference:
- raise IndexError(
- f"Unable to get '{field.mapping}' with '{field.reference}' reference from store."
- f" The available models are {self.store.get_all_model_names()}"
- )
- if not field_is_list:
- if node := get_value(obj, field.mapping):
- if isinstance(node, dict):
- matching_nodes = []
- node_id = node.get("id", None)
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {model} {node_id}")
- node = matching_nodes[0]
- data[field.name] = node.get_unique_id()
- else:
- # Some link are referencing the node identifier directly without the id (i.e location in device)
- data[field.name] = node
-
- else:
- data[field.name] = []
- for node in get_value(obj, field.mapping):
- if not node:
- continue
- node_id = getattr(node, "id", None)
- if not node_id:
- if isinstance(node, tuple):
- node_id = node[1] if node[0] == "id" else None
- if not node_id:
- continue
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {field.reference} {node_id}")
- data[field.name].append(matching_nodes[0].get_unique_id())
- data[field.name] = sorted(data[field.name])
-
- return data
-
-
-class ObserviumModel(DiffSyncModelMixin, DiffSyncModel):
- @classmethod
- def create(
- cls,
- adapter: Adapter,
- ids: Mapping[Any, Any],
- attrs: Mapping[Any, Any],
- ):
- # TODO
- return super().create(adapter=adapter, ids=ids, attrs=attrs)
-
- def update(self, attrs):
- # TODO
- return super().update(attrs)
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/peeringmanager.py b/sync/infrahub-sync/infrahub_sync/adapters/peeringmanager.py
deleted file mode 100644
index 7310a563ae..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/peeringmanager.py
+++ /dev/null
@@ -1,205 +0,0 @@
-from __future__ import annotations
-
-import os
-from typing import Any, Mapping
-
-import requests
-
-from diffsync import Adapter, DiffSyncModel
-from infrahub_sync import (
- DiffSyncMixin,
- DiffSyncModelMixin,
- SchemaMappingModel,
- SyncAdapter,
- SyncConfig,
-)
-
-from .rest_api_client import RestApiClient
-from .utils import derive_identifier_key, get_value
-
-
-class PeeringmanagerAdapter(DiffSyncMixin, Adapter):
- type = "Peeringmanager"
-
- def __init__(self, *args, target: str, adapter: SyncAdapter, config: SyncConfig, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.target = target
- self.client = self._create_rest_client(adapter)
- self.config = config
-
- def _create_rest_client(self, adapter: SyncAdapter) -> RestApiClient:
- settings = adapter.settings or {}
- url = os.environ.get("PEERING_MANAGER_ADDRESS") or os.environ.get("PEERING_MANAGER_URL") or settings.get("url")
- api_endpoint = settings.get("api_endpoint", "/api") # Default endpoint, change if necessary
- auth_method = settings.get("auth_method", "token")
- api_token = os.environ.get("PEERING_MANAGER_TOKEN") or settings.get("token")
- timeout = settings.get("timeout", 30)
-
- if not url:
- raise ValueError("url must be specified!")
-
- if auth_method != "token" or not api_token:
- raise ValueError("Token-based authentication requires a valid API token!")
-
- full_base_url = f"{url.rstrip('/')}/{api_endpoint.strip('/')}"
- return RestApiClient(base_url=full_base_url, auth_method=auth_method, api_token=api_token, timeout=timeout)
-
- def model_loader(self, model_name: str, model: PeeringmanagerModel):
- """
- Load and process models using schema mapping filters and transformations.
-
- This method retrieves data from Peering Manager, applies filters and transformations
- as specified in the schema mapping, and loads the processed data into the adapter.
- """
- # Retrieve schema mapping for this model
- for element in self.config.schema_mapping:
- if not element.name == model_name:
- continue
-
- # Use the resource endpoint from the schema mapping
- resource_name = element.mapping
-
- try:
- # Retrieve all objects
- response_data = self.client.get(resource_name)
- objs = response_data.get("results", [])
- except Exception as exc:
- raise ValueError(f"Error fetching data from REST API: {str(exc)}") from exc
-
- total = len(objs)
- if self.config.source.name.title() == self.type.title():
- # Filter records
- filtered_objs = model.filter_records(records=objs, schema_mapping=element)
- print(f"{self.type}: Loading {len(filtered_objs)}/{total} {resource_name}")
- # Transform records
- transformed_objs = model.transform_records(records=filtered_objs, schema_mapping=element)
- else:
- print(f"{self.type}: Loading all {total} {resource_name}")
- transformed_objs = objs
-
- # Create model instances after filtering and transforming
- for obj in transformed_objs:
- data = self.obj_to_diffsync(obj=obj, mapping=element, model=model)
- item = model(**data)
- self.add(item)
-
- def obj_to_diffsync(self, obj: dict[str, Any], mapping: SchemaMappingModel, model: PeeringmanagerModel) -> dict: # noqa: C901
- obj_id = derive_identifier_key(obj=obj)
- data: dict[str, Any] = {"local_id": str(obj_id)}
-
- for field in mapping.fields:
- field_is_list = model.is_list(name=field.name)
-
- if field.static:
- data[field.name] = field.static
- elif not field_is_list and field.mapping and not field.reference:
- value = get_value(obj, field.mapping)
- if value is not None:
- data[field.name] = value
- elif field_is_list and field.mapping and not field.reference:
- raise NotImplementedError(
- "It's not supported yet to have an attribute of type list with a simple mapping"
- )
- elif field.mapping and field.reference:
- all_nodes_for_reference = self.store.get_all(model=field.reference)
- nodes = [item for item in all_nodes_for_reference]
- if not nodes and all_nodes_for_reference:
- raise IndexError(
- f"Unable to get '{field.mapping}' with '{field.reference}' reference from store."
- f" The available models are {self.store.get_all_model_names()}"
- )
- if not field_is_list:
- if node := get_value(obj, field.mapping):
- if isinstance(node, dict):
- matching_nodes = []
- node_id = node.get("id", None)
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {field.name} {node_id}")
- node = matching_nodes[0]
- data[field.name] = node.get_unique_id()
- else:
- data[field.name] = node
- else:
- data[field.name] = []
- for node in get_value(obj, field.mapping):
- if not node:
- continue
- node_id = node.get("id", None)
- if not node_id:
- if isinstance(node, tuple):
- node_id = node[1] if node[0] == "id" else None
- if not node_id:
- continue
- matching_nodes = [item for item in nodes if item.local_id == str(node_id)]
- if len(matching_nodes) == 0:
- raise IndexError(f"Unable to locate the node {field.reference} {node_id}")
- data[field.name].append(matching_nodes[0].get_unique_id())
- data[field.name] = sorted(data[field.name])
-
- return data
-
-
-class PeeringmanagerModel(DiffSyncModelMixin, DiffSyncModel):
- @classmethod
- def create(
- cls,
- adapter: Adapter,
- ids: Mapping[Any, Any],
- attrs: Mapping[Any, Any],
- ):
- # TODO
- return super().create(adapter=adapter, ids=ids, attrs=attrs)
-
- def update(self, attrs: dict):
- """
- Update an object in the Peering Manager system with new attributes.
-
- This method maps the given attributes to the corresponding target fields
- based on the schema mapping configuration, and sends an update request
- to the API endpoint of the object.
- """
- # Determine the resource name using the schema mapping
- resource_name = self.__class__.get_resource_name(schema_mapping=self.adapter.config.schema_mapping)
-
- # Determine the unique identifier for the API request
- unique_identifier = self.local_id if hasattr(self, "local_id") else self.get_unique_id()
- endpoint = f"{resource_name}/{unique_identifier}/"
-
- # Map incoming attributes to the target attributes based on schema mapping
- mapped_attrs: dict[str, Any] = {}
- for field in self.adapter.config.schema_mapping:
- if field.name == self.__class__.get_type():
- for field_mapping in field.fields:
- # Map source field name to target field name
- if field_mapping.name in attrs:
- target_field_name = field_mapping.mapping
- value = attrs[field_mapping.name]
-
- # Check if the field is a relationship
- if field_mapping.reference:
- all_nodes_for_reference = self.adapter.store.get_all(model=field_mapping.reference)
-
- if isinstance(value, list):
- # For lists, filter nodes to match the unique IDs in the attribute value
- filtered_nodes = [
- node for node in all_nodes_for_reference if node.get_unique_id() in value
- ]
- mapped_attrs[target_field_name] = [node.local_id for node in filtered_nodes]
- else:
- # For single references, find the matching node
- filtered_node = next(
- (node for node in all_nodes_for_reference if node.get_unique_id() == value), None
- )
- if filtered_node:
- mapped_attrs[target_field_name] = filtered_node.local_id
- else:
- mapped_attrs[target_field_name] = value
-
- # Attempt to send the update request to the API
- try:
- self.adapter.client.patch(endpoint, data=mapped_attrs)
- return super().update(attrs)
- except (requests.exceptions.HTTPError, ConnectionError) as exc:
- raise ValueError(f"Error during update: {str(exc)}") from exc
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/rest_api_client.py b/sync/infrahub-sync/infrahub_sync/adapters/rest_api_client.py
deleted file mode 100644
index 31afc60c60..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/rest_api_client.py
+++ /dev/null
@@ -1,90 +0,0 @@
-from typing import Any, Optional
-
-import requests
-
-
-class RestApiClient:
- def __init__(
- self,
- base_url: str,
- auth_method: str,
- api_token: Optional[str] = None,
- username: Optional[str] = None,
- password: Optional[str] = None,
- timeout: Optional[int] = 30,
- ):
- self.base_url = base_url.rstrip("/")
- self.headers = {
- "Content-Type": "application/json",
- "Accept": "application/json",
- }
-
- # Determine authentication method, some are use by more than one API.
- # Example :
- # -> Peering Manager
- if auth_method == "token" and api_token:
- self.headers["Authorization"] = f"Token {api_token}"
- # -> LibreNMS
- elif auth_method == "x-auth-token" and api_token:
- self.headers["X-Auth-Token"] = api_token
- # -> Peering DB
- elif auth_method == "api-key" and api_token:
- self.headers["Authorization"] = f"Api-Key {api_token}"
- # -> RIPE API
- elif auth_method == "key" and api_token:
- self.headers["Authorization"] = f"Key {api_token}"
- # -> Observium
- elif auth_method == "basic" and username and password:
- self.auth = (username, password)
- else:
- raise ValueError("Invalid authentication configuration!")
-
- self.timeout = timeout
-
- def request(
- self, method: str, endpoint: str, params: Optional[dict[str, Any]] = None, data: Optional[dict[str, Any]] = None
- ) -> Any:
- """Make a request to the REST API."""
- url = f"{self.base_url}/{endpoint.lstrip('/')}"
-
- try:
- if hasattr(self, "auth"):
- response = requests.request(
- method=method,
- url=url,
- headers=self.headers,
- params=params,
- json=data,
- auth=self.auth,
- timeout=self.timeout,
- )
- else:
- response = requests.request(
- method=method, url=url, headers=self.headers, params=params, json=data, timeout=self.timeout
- )
-
- response.raise_for_status() # Raise an HTTPError for bad responses
-
- try:
- return response.json()
- except requests.exceptions.JSONDecodeError as exc:
- print("Response content is not valid JSON:", response.text) # Print the response content
- raise ValueError("Response content is not valid JSON.") from exc
-
- except requests.exceptions.RequestException as exc:
- raise ConnectionError(f"API request failed: {str(exc)}") from exc
-
- def get(self, endpoint: str, params: Optional[dict[str, Any]] = None) -> Any:
- return self.request("GET", endpoint, params=params)
-
- def post(self, endpoint: str, data: Optional[dict[str, Any]] = None) -> Any:
- return self.request("POST", endpoint, data=data)
-
- def patch(self, endpoint: str, data: Optional[dict[str, Any]] = None) -> Any:
- return self.request("PATCH", endpoint, data=data)
-
- def put(self, endpoint: str, data: Optional[dict[str, Any]] = None) -> Any:
- return self.request("PUT", endpoint, data=data)
-
- def delete(self, endpoint: str) -> Any:
- return self.request("DELETE", endpoint)
diff --git a/sync/infrahub-sync/infrahub_sync/adapters/utils.py b/sync/infrahub-sync/infrahub_sync/adapters/utils.py
deleted file mode 100644
index eb4f8f515e..0000000000
--- a/sync/infrahub-sync/infrahub_sync/adapters/utils.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from typing import Any, Optional
-
-
-def get_value(obj, name: str):
- """Query a value in dot notation recursively"""
- if "." not in name:
- # Check if the object is a dictionary and use appropriate method to access the attribute.
- if isinstance(obj, dict):
- return obj.get(name)
- return getattr(obj, name, None)
-
- first_name, remaining_part = name.split(".", maxsplit=1)
-
- # Check if the object is a dictionary and use appropriate method to access the attribute.
- if isinstance(obj, dict):
- sub_obj = obj.get(first_name)
- else:
- sub_obj = getattr(obj, first_name, None)
-
- if not sub_obj:
- return None
- return get_value(obj=sub_obj, name=remaining_part)
-
-
-def derive_identifier_key(obj: dict[str, Any]) -> Optional[str]:
- """Try to get obj.id, and if it doesn't exist, try to get a key ending with _id"""
- obj_id = obj.get("id", None)
- if obj_id is None:
- for key, value in obj.items():
- if key.endswith("_id"):
- if value:
- obj_id = value
- break
-
- # If we still didn't find any id, raise ValueError
- if obj_id is None:
- raise ValueError("No suitable identifier key found in object")
- return obj_id
diff --git a/sync/infrahub-sync/infrahub_sync/cli.py b/sync/infrahub-sync/infrahub_sync/cli.py
deleted file mode 100644
index 00121b6018..0000000000
--- a/sync/infrahub-sync/infrahub_sync/cli.py
+++ /dev/null
@@ -1,149 +0,0 @@
-import logging
-from timeit import default_timer as timer
-
-import typer
-from infrahub_sdk import InfrahubClientSync
-from infrahub_sdk.exceptions import ServerNotResponsiveError
-from rich.console import Console
-
-from infrahub_sync.utils import (
- find_missing_schema_model,
- get_all_sync,
- get_instance,
- get_potenda_from_instance,
- render_adapter,
-)
-
-app = typer.Typer()
-console = Console()
-
-logging.basicConfig(level=logging.WARNING)
-
-
-def print_error_and_abort(message: str):
- console.print(f"Error: {message}", style="bold red")
- raise typer.Abort()
-
-
-@app.command(name="list")
-def list_projects(
- directory: str = typer.Option(None, help="Base directory to search for sync configurations"),
-):
- """List all available SYNC projects."""
- for item in get_all_sync(directory=directory):
- console.print(f"{item.name} | {item.source.name} >> {item.destination.name} | {item.directory}")
-
-
-@app.command(name="diff")
-def diff_cmd(
- name: str = typer.Option(default=None, help="Name of the sync to use"),
- config_file: str = typer.Option(default=None, help="File path to the sync configuration YAML file"),
- directory: str = typer.Option(None, help="Base directory to search for sync configurations"),
- branch: str = typer.Option(default=None, help="Branch to use for the diff."),
- show_progress: bool = typer.Option(default=True, help="Show a progress bar during diff"),
-):
- """Calculate and print the differences between the source and the destination systems for a given project."""
- if sum([bool(name), bool(config_file)]) != 1:
- print_error_and_abort("Please specify exactly one of 'name' or 'config-file'.")
-
- sync_instance = get_instance(name=name, config_file=config_file, directory=directory)
- if not sync_instance:
- print_error_and_abort("Failed to load sync instance.")
-
- try:
- ptd = get_potenda_from_instance(sync_instance=sync_instance, branch=branch, show_progress=show_progress)
- except ValueError as exc:
- print_error_and_abort(f"Failed to initialize the Sync Instance: {exc}")
- try:
- ptd.source_load()
- ptd.destination_load()
- except ValueError as exc:
- print_error_and_abort(exc)
-
- mydiff = ptd.diff()
-
- print(mydiff.str())
-
-
-@app.command(name="sync")
-def sync_cmd(
- name: str = typer.Option(default=None, help="Name of the sync to use"),
- config_file: str = typer.Option(default=None, help="File path to the sync configuration YAML file"),
- directory: str = typer.Option(None, help="Base directory to search for sync configurations"),
- branch: str = typer.Option(default=None, help="Branch to use for the sync."),
- diff: bool = typer.Option(
- default=True, help="Print the differences between the source and the destination before syncing"
- ),
- show_progress: bool = typer.Option(default=True, help="Show a progress bar during syncing"),
-):
- """Synchronize the data between source and the destination systems for a given project or configuration file."""
- if sum([bool(name), bool(config_file)]) != 1:
- print_error_and_abort("Please specify exactly one of 'name' or 'config-file'.")
-
- sync_instance = get_instance(name=name, config_file=config_file, directory=directory)
- if not sync_instance:
- print_error_and_abort("Failed to load sync instance.")
-
- try:
- ptd = get_potenda_from_instance(sync_instance=sync_instance, branch=branch, show_progress=show_progress)
- except ValueError as exc:
- print_error_and_abort(f"Failed to initialize the Sync Instance: {exc}")
- try:
- ptd.source_load()
- ptd.destination_load()
- except ValueError as exc:
- print_error_and_abort(exc)
-
- mydiff = ptd.diff()
-
- if mydiff.has_diffs():
- if diff:
- print(mydiff.str())
- start_synctime = timer()
- ptd.sync(diff=mydiff)
- end_synctime = timer()
- console.print(f"Sync: Completed in {end_synctime - start_synctime} sec")
- else:
- console.print("No difference found. Nothing to sync")
-
-
-@app.command(name="generate")
-def generate(
- name: str = typer.Option(default=None, help="Name of the sync to use"),
- config_file: str = typer.Option(default=None, help="File path to the sync configuration YAML file"),
- directory: str = typer.Option(None, help="Base directory to search for sync configurations"),
-):
- """Generate all the python files for a given sync based on the configuration."""
-
- if sum([bool(name), bool(config_file)]) != 1:
- print_error_and_abort("Please specify exactly one of 'name' or 'config_file'.")
-
- sync_instance = get_instance(name=name, config_file=config_file, directory=directory)
- if not sync_instance:
- print_error_and_abort(f"Unable to find the sync {name}. Use the list command to see the sync available")
-
- # TODO
- # - Do not use the env variable token here if token is present in settings
- # - Do not use `main` if the branch is indicated in the file
- infrahub_address = None
- if sync_instance.destination.name == "infrahub":
- if sync_instance.destination.settings and isinstance(sync_instance.source.settings, dict):
- infrahub_address = sync_instance.destination.settings["url"]
- elif sync_instance.source.name == "infrahub":
- if sync_instance.source.settings and isinstance(sync_instance.source.settings, dict):
- infrahub_address = sync_instance.source.settings["url"]
-
- client = InfrahubClientSync(address=infrahub_address)
-
- try:
- schema = client.schema.all()
- except ServerNotResponsiveError as exc:
- print_error_and_abort(str(exc))
-
- missing_schema_models = find_missing_schema_model(sync_instance=sync_instance, schema=schema)
- if missing_schema_models:
- print_error_and_abort(f"One or more model model are not present in the Schema - {missing_schema_models}")
-
- rendered_files = render_adapter(sync_instance=sync_instance, schema=schema)
- for template, output_path in rendered_files:
- console.print(f"Rendered template {template} to {output_path}")
diff --git a/sync/infrahub-sync/infrahub_sync/generator/__init__.py b/sync/infrahub-sync/infrahub_sync/generator/__init__.py
deleted file mode 100644
index e661a31d3e..0000000000
--- a/sync/infrahub-sync/infrahub_sync/generator/__init__.py
+++ /dev/null
@@ -1,173 +0,0 @@
-from pathlib import Path
-from typing import Any, List, Optional, Union
-
-import jinja2
-from infrahub_sdk import (
- AttributeSchema,
- NodeSchema,
- RelationshipKind,
- RelationshipSchema,
-)
-
-from infrahub_sync import SyncConfig
-
-ATTRIBUTE_KIND_MAP = {
- "Text": "str",
- "String": "str",
- "TextArea": "str",
- "DateTime": "str",
- "HashedPassword": "str",
- "Number": "int",
- "Integer": "int",
- "Boolean": "bool",
-}
-
-
-def list_to_set(items: List[str]) -> str:
- """Convert a list in a string representation of a Set."""
- if not items:
- return "()"
-
- response = '"' + '", "'.join(items) + '"'
- if len(items) == 1:
- response += ","
-
- return "(" + response + ")"
-
-
-def list_to_str(items: List[str]) -> str:
- """Convert a list into a string separated with comma"""
- return ", ".join(items)
-
-
-def has_node(config: SyncConfig, name: str) -> bool:
- for item in config.schema_mapping:
- if item.name == name:
- return True
- return False
-
-
-def has_field(config: SyncConfig, name: str, field: str) -> bool:
- for item in config.schema_mapping:
- if item.name == name:
- for subitem in item.fields:
- if subitem.name == field:
- return True
- return False
-
-
-def get_identifiers(node: NodeSchema, config: SyncConfig) -> Optional[List[str]]:
- """Return the identifiers that should be used by DiffSync."""
-
- config_identifiers = [
- item.identifiers for item in config.schema_mapping if item.name == node.kind and item.identifiers
- ]
-
- if config_identifiers:
- return config_identifiers[0]
-
- identifiers = [
- attr.name for attr in node.attributes if attr.unique and has_field(config, name=node.kind, field=attr.name)
- ]
-
- if not identifiers:
- return None
-
- return identifiers
-
-
-def get_attributes(node: NodeSchema, config: SyncConfig) -> Optional[List[str]]:
- """Return the attributes that should be used by DiffSync."""
- attrs_attributes = [attr.name for attr in node.attributes if has_field(config, name=node.kind, field=attr.name)]
- rels_identifiers = [
- rel.name
- for rel in node.relationships
- if rel.kind != RelationshipKind.COMPONENT and has_field(config, name=node.kind, field=rel.name)
- ]
-
- identifiers = get_identifiers(node=node, config=config)
- if not identifiers:
- return None
-
- attributes = [item for item in rels_identifiers + attrs_attributes if item not in identifiers]
-
- if not attributes:
- return None
-
- return attributes
-
-
-def get_children(node: NodeSchema, config: SyncConfig) -> Optional[str]:
- # rel.peer.lower() might now work in all cases we should have a better function to convert that
- children = {
- rel.peer.lower(): rel.name
- for rel in node.relationships
- if rel.cardinality == "many"
- and rel.kind == RelationshipKind.COMPONENT
- and has_field(config, name=node.kind, field=rel.name)
- }
-
- if not children:
- return None
-
- children_list = [f'"{key}": "{value}"' for key, value in children.items()]
- return "{" + ", ".join(children_list) + "}"
-
-
-def get_kind(item: Union[RelationshipSchema, AttributeSchema]) -> str:
- kind = "str"
- if isinstance(item, AttributeSchema):
- kind = ATTRIBUTE_KIND_MAP.get(item.kind, "str")
- if item.optional:
- kind = f"Optional[{kind}]"
- if item.default_value is not None:
- # Format the default value based on its type
- if isinstance(item.default_value, str):
- kind += f' = "{item.default_value}"'
- elif isinstance(item.default_value, (int, float, bool)):
- kind += f" = {item.default_value}"
- else:
- kind += f" = {repr(item.default_value)}"
- else:
- kind += " = None"
-
- elif isinstance(item, RelationshipSchema) and item.cardinality == "one":
- if item.optional:
- kind = f"Optional[{kind}] = None"
-
- elif isinstance(item, RelationshipSchema) and item.cardinality == "many":
- kind = "List[str]"
- if item.optional:
- kind = f"Optional[{kind}]"
- kind += " = []"
-
- return kind
-
-
-def has_children(node: NodeSchema, config: SyncConfig) -> bool:
- if get_children(config=config, node=node):
- return True
- return False
-
-
-def render_template(template_file: Path, output_dir: Path, output_file: Path, context: dict[str, Any]):
- template_loader = jinja2.PackageLoader("infrahub_sync", "generator/templates")
- template_env = jinja2.Environment(
- loader=template_loader,
- )
- # Add custom filters to Jinja2
- template_env.filters["get_identifiers"] = get_identifiers
- template_env.filters["get_attributes"] = get_attributes
- template_env.filters["get_children"] = get_children
- template_env.filters["list_to_set"] = list_to_set
- template_env.filters["list_to_str"] = list_to_str
- template_env.filters["has_node"] = has_node
- template_env.filters["has_field"] = has_field
- template_env.filters["has_children"] = has_children
- template_env.filters["get_kind"] = get_kind
-
- template = template_env.get_template(str(template_file))
-
- rendered_tpl = template.render(**context) # type: ignore[arg-type]
- output_filename = output_dir / output_file
- output_filename.write_text(rendered_tpl, encoding="utf-8")
diff --git a/sync/infrahub-sync/infrahub_sync/generator/templates/diffsync_adapter.j2 b/sync/infrahub-sync/infrahub_sync/generator/templates/diffsync_adapter.j2
deleted file mode 100644
index 2c9bbb7430..0000000000
--- a/sync/infrahub-sync/infrahub_sync/generator/templates/diffsync_adapter.j2
+++ /dev/null
@@ -1,20 +0,0 @@
-from infrahub_sync.adapters.{{ adapter.name }} import {{ adapter.name.title() }}Adapter
-
-from .sync_models import (
-{% for nodekind, node in schema.items()|sort() %}
-{%- if node | get_identifiers(config) %} {{ nodekind }},
-{% endif -%}
-{% endfor -%}
-)
-
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-class {{ adapter.name.title() }}Sync({{ adapter.name.title() }}Adapter):
-{% for nodekind, node in schema.items() -%}
-{%- if node | get_identifiers(config) %} {{ node.kind }} = {{ nodekind }}
-{% endif -%}
-{% endfor %}
diff --git a/sync/infrahub-sync/infrahub_sync/generator/templates/diffsync_models.j2 b/sync/infrahub-sync/infrahub_sync/generator/templates/diffsync_models.j2
deleted file mode 100644
index a200a187b3..0000000000
--- a/sync/infrahub-sync/infrahub_sync/generator/templates/diffsync_models.j2
+++ /dev/null
@@ -1,31 +0,0 @@
-from typing import Any, List, Optional
-
-from infrahub_sync.adapters.{{ adapter.name }} import {{ adapter.name.title() }}Model
-
-# -------------------------------------------------------
-# AUTO-GENERATED FILE, DO NOT MODIFY
-# This file has been generated with the command `infrahub-sync generate`
-# All modifications will be lost the next time you reexecute this command
-# -------------------------------------------------------
-{%- for nodekind, node in schema.items() -%}
-{%- if node | get_identifiers(config) and config | has_node(node.kind) %}
-class {{ nodekind }}({{ adapter.name.title() }}Model):
- _modelname = "{{ node.kind }}"
- _identifiers = {{ node | get_identifiers(config) | list_to_set }}
- _attributes = {{ node | get_attributes(config) | list_to_set }}
-
-{%- for attr in node.attributes -%}
-{%- if config | has_field(node.kind, attr.name) %}
- {{ attr.name }}: {{ attr | get_kind }}
-{%- endif -%}
-{%- endfor -%}
-{%- for rel in node.relationships -%}
-{%- if config | has_field(node.kind, rel.name) %}
- {{ rel.name }}: {{ rel | get_kind }}
-{%- endif -%}
-{%- endfor %}
-
- local_id: Optional[str] = None
- local_data: Optional[Any] = None
-{% endif %}
-{%- endfor %}
diff --git a/sync/infrahub-sync/infrahub_sync/utils.py b/sync/infrahub-sync/infrahub_sync/utils.py
deleted file mode 100644
index 05cc0ebecc..0000000000
--- a/sync/infrahub-sync/infrahub_sync/utils.py
+++ /dev/null
@@ -1,188 +0,0 @@
-import importlib
-import sys
-from pathlib import Path
-from typing import List, MutableMapping, Optional, Tuple, Union
-
-import yaml
-from infrahub_sdk.schema import GenericSchema, NodeSchema
-
-from diffsync.store.local import LocalStore
-from diffsync.store.redis import RedisStore
-from infrahub_sync import SyncAdapter, SyncConfig, SyncInstance
-from infrahub_sync.generator import render_template
-from potenda import Potenda
-
-
-def find_missing_schema_model(
- sync_instance: SyncInstance, schema: MutableMapping[str, Union[NodeSchema, GenericSchema]]
-) -> List[str]:
- missing_schema_models = []
- for item in sync_instance.schema_mapping:
- match_found = any(item.name == node.kind for node in schema.values())
-
- if not match_found:
- missing_schema_models.append(item.name)
-
- return missing_schema_models
-
-
-def render_adapter(
- sync_instance: SyncInstance, schema: MutableMapping[str, Union[NodeSchema, GenericSchema]]
-) -> List[Tuple[str, str]]:
- files_to_render = (
- ("diffsync_models.j2", "sync_models.py"),
- ("diffsync_adapter.j2", "sync_adapter.py"),
- )
- rendered_files = []
- for adapter in [sync_instance.source, sync_instance.destination]:
- output_dir_path = Path(sync_instance.directory, adapter.name)
- if not output_dir_path.is_dir():
- output_dir_path.mkdir(exist_ok=True)
-
- init_file_path = output_dir_path / "__init__.py"
- if not init_file_path.exists():
- init_file_path.touch()
-
- for item in files_to_render:
- render_template(
- template_file=item[0],
- output_dir=output_dir_path,
- output_file=item[1],
- context={"schema": schema, "adapter": adapter, "config": sync_instance},
- )
- output_file_path = output_dir_path / item[1]
- rendered_files.append((item[0], output_file_path))
-
- return rendered_files
-
-
-def import_adapter(sync_instance: SyncInstance, adapter: SyncAdapter):
- directory = Path(sync_instance.directory)
- sys.path.insert(0, str(directory))
- adapter_file_path = directory / f"{adapter.name}" / "sync_adapter.py"
-
- try:
- adapter_name = f"{adapter.name.title()}Sync"
- spec = importlib.util.spec_from_file_location(f"{adapter.name}.adapter", str(adapter_file_path))
- adapter_module = importlib.util.module_from_spec(spec)
- sys.modules[f"{adapter.name}.adapter"] = adapter_module
- spec.loader.exec_module(adapter_module)
-
- adapter_class = getattr(adapter_module, adapter_name, None)
- if adapter_class is None:
- raise AttributeError(f"{adapter_name} not found in adapter.py")
- except (FileNotFoundError, AttributeError) as exc:
- raise ImportError(f"{adapter_name}: {str(exc)}") from exc
- return adapter_class
-
-
-def get_all_sync(directory: Optional[str] = None) -> List[SyncInstance]:
- results = []
- search_directory = Path(directory) if directory else Path(__file__).parent
- config_files = search_directory.glob("**/config.yml")
-
- for config_file in config_files:
- with config_file.open("r") as file:
- directory_name = str(config_file.parent)
- config_data = yaml.safe_load(file)
- SyncConfig(**config_data)
- results.append(SyncInstance(**config_data, directory=directory_name))
-
- return results
-
-
-def get_instance(
- name: Optional[str] = None, config_file: Optional[str] = "config.yml", directory: Optional[str] = None
-) -> Optional[SyncInstance]:
- if name:
- all_sync_instances = get_all_sync(directory=directory)
- for item in all_sync_instances:
- if item.name == name:
- return item
- return None
-
- config_file_path = None
- try:
- if Path(config_file).is_absolute() or directory is None:
- config_file_path = Path(config_file)
- elif directory:
- config_file_path = Path(directory, config_file)
- except TypeError:
- # TODO Log or raise an Error/Warning
- return None
-
- if config_file_path:
- directory_path = config_file_path.parent
- if config_file_path.is_file():
- with config_file_path.open("r", encoding="UTF-8") as file:
- config_data = yaml.safe_load(file)
- return SyncInstance(**config_data, directory=str(directory_path))
-
- return None
-
-
-def get_potenda_from_instance(
- sync_instance: SyncInstance, branch: Optional[str] = None, show_progress: Optional[bool] = True
-) -> Potenda:
- source = import_adapter(sync_instance=sync_instance, adapter=sync_instance.source)
- destination = import_adapter(sync_instance=sync_instance, adapter=sync_instance.destination)
-
- source_store = LocalStore()
- destination_store = LocalStore()
-
- if sync_instance.store:
- if sync_instance.store.type == "redis":
- if sync_instance.store.settings and isinstance(sync_instance.store.settings, dict):
- redis_settings = sync_instance.store.settings
- source_store = RedisStore(**redis_settings, name=sync_instance.source.name)
- destination_store = RedisStore(**redis_settings, name=sync_instance.destination.name)
- else:
- source_store = RedisStore(name=sync_instance.source.name)
- destination_store = RedisStore(name=sync_instance.destination.name)
-
- try:
- if sync_instance.source.name == "infrahub" and branch:
- src = source(
- config=sync_instance,
- target="source",
- adapter=sync_instance.source,
- branch=branch,
- internal_storage_engine=source_store,
- )
- else:
- src = source(
- config=sync_instance,
- target="source",
- adapter=sync_instance.source,
- internal_storage_engine=source_store,
- )
- except ValueError as exc:
- raise ValueError(f"{sync_instance.source.name.title()}Adapter - {exc}") from exc
- try:
- if sync_instance.destination.name == "infrahub" and branch:
- dst = destination(
- config=sync_instance,
- target="destination",
- adapter=sync_instance.destination,
- branch=branch,
- internal_storage_engine=destination_store,
- )
- else:
- dst = destination(
- config=sync_instance,
- target="destination",
- adapter=sync_instance.destination,
- internal_storage_engine=destination_store,
- )
- except ValueError as exc:
- raise ValueError(f"{sync_instance.destination.name.title()}Adapter - {exc}") from exc
-
- ptd = Potenda(
- destination=dst,
- source=src,
- config=sync_instance,
- top_level=sync_instance.order,
- show_progress=show_progress,
- )
-
- return ptd
diff --git a/sync/infrahub-sync/tests/__init__.py b/sync/infrahub-sync/tests/__init__.py
deleted file mode 100644
index 9c48bcf96d..0000000000
--- a/sync/infrahub-sync/tests/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import builtins
-
-from rich import print as rprint
-
-builtins.rprint = rprint # type: ignore
diff --git a/sync/poetry.lock b/sync/poetry.lock
deleted file mode 100644
index af9b623798..0000000000
--- a/sync/poetry.lock
+++ /dev/null
@@ -1,2085 +0,0 @@
-# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
-
-[[package]]
-name = "annotated-types"
-version = "0.7.0"
-description = "Reusable constraint types to use with typing.Annotated"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
- {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
-]
-
-[[package]]
-name = "anyio"
-version = "4.4.0"
-description = "High level compatibility layer for multiple asynchronous event loop implementations"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"},
- {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"},
-]
-
-[package.dependencies]
-exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""}
-idna = ">=2.8"
-sniffio = ">=1.1"
-typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
-
-[package.extras]
-doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
-test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
-trio = ["trio (>=0.23)"]
-
-[[package]]
-name = "astroid"
-version = "3.2.2"
-description = "An abstract syntax tree for Python with inference support."
-optional = false
-python-versions = ">=3.8.0"
-files = [
- {file = "astroid-3.2.2-py3-none-any.whl", hash = "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0"},
- {file = "astroid-3.2.2.tar.gz", hash = "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94"},
-]
-
-[package.dependencies]
-typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
-
-[[package]]
-name = "asttokens"
-version = "2.4.1"
-description = "Annotate AST trees with source code positions"
-optional = false
-python-versions = "*"
-files = [
- {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"},
- {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"},
-]
-
-[package.dependencies]
-six = ">=1.12.0"
-
-[package.extras]
-astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"]
-test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"]
-
-[[package]]
-name = "async-timeout"
-version = "4.0.3"
-description = "Timeout context manager for asyncio programs"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
- {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
-]
-
-[[package]]
-name = "certifi"
-version = "2024.7.4"
-description = "Python package for providing Mozilla's CA Bundle."
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
- {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
-]
-
-[[package]]
-name = "cfgv"
-version = "3.4.0"
-description = "Validate configuration and produce human readable error messages."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
- {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
-]
-
-[[package]]
-name = "charset-normalizer"
-version = "3.3.2"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-optional = false
-python-versions = ">=3.7.0"
-files = [
- {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"},
- {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"},
- {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"},
- {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"},
- {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"},
- {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"},
- {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"},
- {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
-]
-
-[[package]]
-name = "click"
-version = "8.1.7"
-description = "Composable command line interface toolkit"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
- {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[[package]]
-name = "colorama"
-version = "0.4.6"
-description = "Cross-platform colored terminal text."
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-files = [
- {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
- {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
-]
-
-[[package]]
-name = "coverage"
-version = "7.5.3"
-description = "Code coverage measurement for Python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"},
- {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"},
- {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"},
- {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"},
- {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"},
- {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"},
- {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"},
- {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"},
- {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"},
- {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"},
- {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"},
- {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"},
- {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"},
- {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"},
- {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"},
- {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"},
- {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"},
- {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"},
- {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"},
- {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"},
- {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"},
- {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"},
- {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"},
- {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"},
- {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"},
- {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"},
- {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"},
- {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"},
- {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"},
- {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"},
- {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"},
- {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"},
- {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"},
- {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"},
- {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"},
- {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"},
- {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"},
- {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"},
- {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"},
- {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"},
- {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"},
- {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"},
- {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"},
- {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"},
- {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"},
- {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"},
- {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"},
- {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"},
- {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"},
- {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"},
- {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"},
- {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"},
-]
-
-[package.dependencies]
-tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
-
-[package.extras]
-toml = ["tomli"]
-
-[[package]]
-name = "decorator"
-version = "5.1.1"
-description = "Decorators for Humans"
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
- {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
-]
-
-[[package]]
-name = "diffsync"
-version = "2.0.0"
-description = "Library to easily sync/diff/update 2 different data sources"
-optional = false
-python-versions = ">=3.8,<4.0"
-files = [
- {file = "diffsync-2.0.0-py3-none-any.whl", hash = "sha256:59f864a115abc5b0aa3b9db0d44deff59c81cd5469e5894326c27e29511e3aab"},
- {file = "diffsync-2.0.0.tar.gz", hash = "sha256:712bc85a24f49ef6075344dc3a16c85e27b1416154c46fd5de7acf72e8321a9b"},
-]
-
-[package.dependencies]
-colorama = ">=0.4.3,<0.5.0"
-packaging = ">=21.3,<24.0"
-pydantic = ">=2.0.0,<3.0.0"
-redis = {version = ">=4.3,<5.0", optional = true, markers = "extra == \"redis\""}
-structlog = ">=20.1.0,<23.0.0"
-typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
-
-[package.extras]
-redis = ["redis (>=4.3,<5.0)"]
-
-[[package]]
-name = "dill"
-version = "0.3.8"
-description = "serialize all of Python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"},
- {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"},
-]
-
-[package.extras]
-graph = ["objgraph (>=1.7.2)"]
-profile = ["gprof2dot (>=2022.7.29)"]
-
-[[package]]
-name = "distlib"
-version = "0.3.8"
-description = "Distribution utilities"
-optional = false
-python-versions = "*"
-files = [
- {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
- {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
-]
-
-[[package]]
-name = "exceptiongroup"
-version = "1.2.1"
-description = "Backport of PEP 654 (exception groups)"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
- {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
-]
-
-[package.extras]
-test = ["pytest (>=6)"]
-
-[[package]]
-name = "execnet"
-version = "2.1.1"
-description = "execnet: rapid multi-Python deployment"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"},
- {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"},
-]
-
-[package.extras]
-testing = ["hatch", "pre-commit", "pytest", "tox"]
-
-[[package]]
-name = "executing"
-version = "2.0.1"
-description = "Get the currently executing AST node of a frame, and other information"
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"},
- {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"},
-]
-
-[package.extras]
-tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
-
-[[package]]
-name = "filelock"
-version = "3.15.1"
-description = "A platform independent file lock."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "filelock-3.15.1-py3-none-any.whl", hash = "sha256:71b3102950e91dfc1bb4209b64be4dc8854f40e5f534428d8684f953ac847fac"},
- {file = "filelock-3.15.1.tar.gz", hash = "sha256:58a2549afdf9e02e10720eaa4d4470f56386d7a6f72edd7d0596337af8ed7ad8"},
-]
-
-[package.extras]
-docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
-typing = ["typing-extensions (>=4.8)"]
-
-[[package]]
-name = "gitdb"
-version = "4.0.11"
-description = "Git Object Database"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"},
- {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"},
-]
-
-[package.dependencies]
-smmap = ">=3.0.1,<6"
-
-[[package]]
-name = "gitpython"
-version = "3.1.43"
-description = "GitPython is a Python library used to interact with Git repositories"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"},
- {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"},
-]
-
-[package.dependencies]
-gitdb = ">=4.0.1,<5"
-
-[package.extras]
-doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"]
-test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"]
-
-[[package]]
-name = "graphql-core"
-version = "3.2.3"
-description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL."
-optional = false
-python-versions = ">=3.6,<4"
-files = [
- {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"},
- {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"},
-]
-
-[[package]]
-name = "h11"
-version = "0.14.0"
-description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
- {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
-]
-
-[[package]]
-name = "httpcore"
-version = "1.0.5"
-description = "A minimal low-level HTTP client."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"},
- {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"},
-]
-
-[package.dependencies]
-certifi = "*"
-h11 = ">=0.13,<0.15"
-
-[package.extras]
-asyncio = ["anyio (>=4.0,<5.0)"]
-http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (==1.*)"]
-trio = ["trio (>=0.22.0,<0.26.0)"]
-
-[[package]]
-name = "httpx"
-version = "0.27.0"
-description = "The next generation HTTP client."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"},
- {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"},
-]
-
-[package.dependencies]
-anyio = "*"
-certifi = "*"
-httpcore = "==1.*"
-idna = "*"
-sniffio = "*"
-
-[package.extras]
-brotli = ["brotli", "brotlicffi"]
-cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
-http2 = ["h2 (>=3,<5)"]
-socks = ["socksio (==1.*)"]
-
-[[package]]
-name = "identify"
-version = "2.5.36"
-description = "File identification library for Python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"},
- {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"},
-]
-
-[package.extras]
-license = ["ukkonen"]
-
-[[package]]
-name = "idna"
-version = "3.7"
-description = "Internationalized Domain Names in Applications (IDNA)"
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
- {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
-]
-
-[[package]]
-name = "infrahub-sdk"
-version = "0.12.2"
-description = "Python Client to interact with Infrahub"
-optional = false
-python-versions = "<4.0,>=3.9"
-files = [
- {file = "infrahub_sdk-0.12.2-py3-none-any.whl", hash = "sha256:d5469f96d0ed6260266f74cbe0ae2dc62b28d37635862f0a0825d90be8836afe"},
- {file = "infrahub_sdk-0.12.2.tar.gz", hash = "sha256:627cb26ec619824ccc44aded3853c8514245e81dc62ae336ea219d8371e1064a"},
-]
-
-[package.dependencies]
-gitpython = ">=3,<4"
-graphql-core = ">=3.1,<3.3"
-httpx = [
- {version = ">=0.20", markers = "python_version >= \"3.9\" and python_version < \"3.11\""},
- {version = ">=0.23", markers = "python_version >= \"3.11\""},
-]
-Jinja2 = {version = ">=3,<4", optional = true, markers = "extra == \"ctl\" or extra == \"tests\" or extra == \"all\""}
-numpy = [
- {version = ">=1.24.2,<2.0.0", optional = true, markers = "python_version >= \"3.9\" and python_version < \"3.12\" and extra == \"ctl\" or python_version >= \"3.9\" and python_version < \"3.12\" and extra == \"all\""},
- {version = ">=1.26.2,<2.0.0", optional = true, markers = "python_version >= \"3.12\" and extra == \"ctl\" or python_version >= \"3.12\" and extra == \"all\""},
-]
-pendulum = [
- {version = ">=2", markers = "python_version >= \"3.9\" and python_version < \"3.12\""},
- {version = ">=3", markers = "python_version >= \"3.12\""},
-]
-pyarrow = {version = ">=14,<15", optional = true, markers = "extra == \"ctl\" or extra == \"all\""}
-pydantic = ">=2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
-pydantic-settings = ">=2.0"
-pytest = {version = "*", optional = true, markers = "extra == \"tests\" or extra == \"all\""}
-pyyaml = {version = ">=6,<7", optional = true, markers = "extra == \"ctl\" or extra == \"tests\" or extra == \"all\""}
-rich = {version = ">=13,<14", optional = true, markers = "extra == \"ctl\" or extra == \"tests\" or extra == \"all\""}
-toml = {version = ">=0.10,<0.11", optional = true, markers = "extra == \"ctl\" or extra == \"all\""}
-typer = {version = ">=0,<1", optional = true, markers = "extra == \"ctl\" or extra == \"all\""}
-ujson = ">=5,<6"
-
-[package.extras]
-all = ["Jinja2 (>=3,<4)", "numpy (>=1.24.2,<2.0.0)", "numpy (>=1.26.2,<2.0.0)", "pyarrow (>=14,<15)", "pytest", "pyyaml (>=6,<7)", "rich (>=13,<14)", "toml (>=0.10,<0.11)", "typer (>=0,<1)"]
-ctl = ["Jinja2 (>=3,<4)", "numpy (>=1.24.2,<2.0.0)", "numpy (>=1.26.2,<2.0.0)", "pyarrow (>=14,<15)", "pyyaml (>=6,<7)", "rich (>=13,<14)", "toml (>=0.10,<0.11)", "typer (>=0,<1)"]
-tests = ["Jinja2 (>=3,<4)", "pytest", "pyyaml (>=6,<7)", "rich (>=13,<14)"]
-
-[[package]]
-name = "iniconfig"
-version = "2.0.0"
-description = "brain-dead simple config-ini parsing"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
- {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
-]
-
-[[package]]
-name = "ipython"
-version = "8.18.1"
-description = "IPython: Productive Interactive Computing"
-optional = false
-python-versions = ">=3.9"
-files = [
- {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"},
- {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "sys_platform == \"win32\""}
-decorator = "*"
-exceptiongroup = {version = "*", markers = "python_version < \"3.11\""}
-jedi = ">=0.16"
-matplotlib-inline = "*"
-pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
-prompt-toolkit = ">=3.0.41,<3.1.0"
-pygments = ">=2.4.0"
-stack-data = "*"
-traitlets = ">=5"
-typing-extensions = {version = "*", markers = "python_version < \"3.10\""}
-
-[package.extras]
-all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"]
-black = ["black"]
-doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"]
-kernel = ["ipykernel"]
-nbconvert = ["nbconvert"]
-nbformat = ["nbformat"]
-notebook = ["ipywidgets", "notebook"]
-parallel = ["ipyparallel"]
-qtconsole = ["qtconsole"]
-test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"]
-test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"]
-
-[[package]]
-name = "isort"
-version = "5.13.2"
-description = "A Python utility / library to sort Python imports."
-optional = false
-python-versions = ">=3.8.0"
-files = [
- {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
- {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
-]
-
-[package.extras]
-colors = ["colorama (>=0.4.6)"]
-
-[[package]]
-name = "jedi"
-version = "0.19.1"
-description = "An autocompletion tool for Python that can be used for text editors."
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"},
- {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"},
-]
-
-[package.dependencies]
-parso = ">=0.8.3,<0.9.0"
-
-[package.extras]
-docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
-qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
-testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
-
-[[package]]
-name = "jinja2"
-version = "3.1.4"
-description = "A very fast and expressive template engine."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
- {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
-]
-
-[package.dependencies]
-MarkupSafe = ">=2.0"
-
-[package.extras]
-i18n = ["Babel (>=2.7)"]
-
-[[package]]
-name = "markdown-it-py"
-version = "3.0.0"
-description = "Python port of markdown-it. Markdown parsing, done right!"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
- {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
-]
-
-[package.dependencies]
-mdurl = ">=0.1,<1.0"
-
-[package.extras]
-benchmarking = ["psutil", "pytest", "pytest-benchmark"]
-code-style = ["pre-commit (>=3.0,<4.0)"]
-compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
-linkify = ["linkify-it-py (>=1,<3)"]
-plugins = ["mdit-py-plugins"]
-profiling = ["gprof2dot"]
-rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
-testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
-
-[[package]]
-name = "markupsafe"
-version = "2.1.5"
-description = "Safely add untrusted strings to HTML/XML markup."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
- {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
- {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
- {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"},
- {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"},
- {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"},
- {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"},
- {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
-]
-
-[[package]]
-name = "matplotlib-inline"
-version = "0.1.7"
-description = "Inline Matplotlib backend for Jupyter"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"},
- {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"},
-]
-
-[package.dependencies]
-traitlets = "*"
-
-[[package]]
-name = "mccabe"
-version = "0.7.0"
-description = "McCabe checker, plugin for flake8"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
- {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
-]
-
-[[package]]
-name = "mdurl"
-version = "0.1.2"
-description = "Markdown URL utilities"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
- {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
-]
-
-[[package]]
-name = "mypy"
-version = "1.10.0"
-description = "Optional static typing for Python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"},
- {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"},
- {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"},
- {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"},
- {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"},
- {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"},
- {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"},
- {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"},
- {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"},
- {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"},
- {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"},
- {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"},
- {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"},
- {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"},
- {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"},
- {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"},
- {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"},
- {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"},
- {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"},
- {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"},
- {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"},
- {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"},
- {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"},
- {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"},
- {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"},
- {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"},
- {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"},
-]
-
-[package.dependencies]
-mypy-extensions = ">=1.0.0"
-tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typing-extensions = ">=4.1.0"
-
-[package.extras]
-dmypy = ["psutil (>=4.0)"]
-install-types = ["pip"]
-mypyc = ["setuptools (>=50)"]
-reports = ["lxml"]
-
-[[package]]
-name = "mypy-extensions"
-version = "1.0.0"
-description = "Type system extensions for programs checked with the mypy type checker."
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
- {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
-]
-
-[[package]]
-name = "netutils"
-version = "1.9.1"
-description = "Common helper functions useful in network automation."
-optional = false
-python-versions = "<4.0,>=3.8"
-files = [
- {file = "netutils-1.9.1-py3-none-any.whl", hash = "sha256:0d6e9026cc529f365a63377159aed07769baee0bf7a7138fa86fce37b64dd9d4"},
- {file = "netutils-1.9.1.tar.gz", hash = "sha256:8ad8b5e02eb9d6692d0aaaf9c0f36da1a81f520f426a79d0e08e56cf7dbb3476"},
-]
-
-[package.extras]
-optionals = ["jsonschema (>=4.17.3,<5.0.0)", "napalm (>=4.0.0,<5.0.0)"]
-
-[[package]]
-name = "nodeenv"
-version = "1.9.1"
-description = "Node.js virtual environment builder"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-files = [
- {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
- {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
-]
-
-[[package]]
-name = "numpy"
-version = "1.26.4"
-description = "Fundamental package for array computing in Python"
-optional = false
-python-versions = ">=3.9"
-files = [
- {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"},
- {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"},
- {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"},
- {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"},
- {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"},
- {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"},
- {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"},
- {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"},
- {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"},
- {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"},
- {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"},
- {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"},
- {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"},
- {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"},
- {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"},
- {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"},
- {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"},
- {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"},
- {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"},
- {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"},
- {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"},
- {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"},
- {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"},
- {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"},
- {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"},
- {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"},
- {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"},
- {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"},
- {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"},
- {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"},
- {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"},
- {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"},
- {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"},
- {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"},
- {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"},
- {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
-]
-
-[[package]]
-name = "packaging"
-version = "23.2"
-description = "Core utilities for Python packages"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
- {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
-]
-
-[[package]]
-name = "parso"
-version = "0.8.4"
-description = "A Python Parser"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"},
- {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"},
-]
-
-[package.extras]
-qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
-testing = ["docopt", "pytest"]
-
-[[package]]
-name = "pathspec"
-version = "0.12.1"
-description = "Utility library for gitignore style pattern matching of file paths."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
- {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
-]
-
-[[package]]
-name = "pendulum"
-version = "3.0.0"
-description = "Python datetimes made easy"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pendulum-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2cf9e53ef11668e07f73190c805dbdf07a1939c3298b78d5a9203a86775d1bfd"},
- {file = "pendulum-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb551b9b5e6059377889d2d878d940fd0bbb80ae4810543db18e6f77b02c5ef6"},
- {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c58227ac260d5b01fc1025176d7b31858c9f62595737f350d22124a9a3ad82d"},
- {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60fb6f415fea93a11c52578eaa10594568a6716602be8430b167eb0d730f3332"},
- {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b69f6b4dbcb86f2c2fe696ba991e67347bcf87fe601362a1aba6431454b46bde"},
- {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:138afa9c373ee450ede206db5a5e9004fd3011b3c6bbe1e57015395cd076a09f"},
- {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:83d9031f39c6da9677164241fd0d37fbfc9dc8ade7043b5d6d62f56e81af8ad2"},
- {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c2308af4033fa534f089595bcd40a95a39988ce4059ccd3dc6acb9ef14ca44a"},
- {file = "pendulum-3.0.0-cp310-none-win_amd64.whl", hash = "sha256:9a59637cdb8462bdf2dbcb9d389518c0263799189d773ad5c11db6b13064fa79"},
- {file = "pendulum-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3725245c0352c95d6ca297193192020d1b0c0f83d5ee6bb09964edc2b5a2d508"},
- {file = "pendulum-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c035f03a3e565ed132927e2c1b691de0dbf4eb53b02a5a3c5a97e1a64e17bec"},
- {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597e66e63cbd68dd6d58ac46cb7a92363d2088d37ccde2dae4332ef23e95cd00"},
- {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99a0f8172e19f3f0c0e4ace0ad1595134d5243cf75985dc2233e8f9e8de263ca"},
- {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77d8839e20f54706aed425bec82a83b4aec74db07f26acd039905d1237a5e1d4"},
- {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afde30e8146292b059020fbc8b6f8fd4a60ae7c5e6f0afef937bbb24880bdf01"},
- {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:660434a6fcf6303c4efd36713ca9212c753140107ee169a3fc6c49c4711c2a05"},
- {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dee9e5a48c6999dc1106eb7eea3e3a50e98a50651b72c08a87ee2154e544b33e"},
- {file = "pendulum-3.0.0-cp311-none-win_amd64.whl", hash = "sha256:d4cdecde90aec2d67cebe4042fd2a87a4441cc02152ed7ed8fb3ebb110b94ec4"},
- {file = "pendulum-3.0.0-cp311-none-win_arm64.whl", hash = "sha256:773c3bc4ddda2dda9f1b9d51fe06762f9200f3293d75c4660c19b2614b991d83"},
- {file = "pendulum-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:409e64e41418c49f973d43a28afe5df1df4f1dd87c41c7c90f1a63f61ae0f1f7"},
- {file = "pendulum-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a38ad2121c5ec7c4c190c7334e789c3b4624798859156b138fcc4d92295835dc"},
- {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fde4d0b2024b9785f66b7f30ed59281bd60d63d9213cda0eb0910ead777f6d37"},
- {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b2c5675769fb6d4c11238132962939b960fcb365436b6d623c5864287faa319"},
- {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8af95e03e066826f0f4c65811cbee1b3123d4a45a1c3a2b4fc23c4b0dff893b5"},
- {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2165a8f33cb15e06c67070b8afc87a62b85c5a273e3aaa6bc9d15c93a4920d6f"},
- {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ad5e65b874b5e56bd942546ea7ba9dd1d6a25121db1c517700f1c9de91b28518"},
- {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17fe4b2c844bbf5f0ece69cfd959fa02957c61317b2161763950d88fed8e13b9"},
- {file = "pendulum-3.0.0-cp312-none-win_amd64.whl", hash = "sha256:78f8f4e7efe5066aca24a7a57511b9c2119f5c2b5eb81c46ff9222ce11e0a7a5"},
- {file = "pendulum-3.0.0-cp312-none-win_arm64.whl", hash = "sha256:28f49d8d1e32aae9c284a90b6bb3873eee15ec6e1d9042edd611b22a94ac462f"},
- {file = "pendulum-3.0.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:d4e2512f4e1a4670284a153b214db9719eb5d14ac55ada5b76cbdb8c5c00399d"},
- {file = "pendulum-3.0.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:3d897eb50883cc58d9b92f6405245f84b9286cd2de6e8694cb9ea5cb15195a32"},
- {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e169cc2ca419517f397811bbe4589cf3cd13fca6dc38bb352ba15ea90739ebb"},
- {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17c3084a4524ebefd9255513692f7e7360e23c8853dc6f10c64cc184e1217ab"},
- {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:826d6e258052715f64d05ae0fc9040c0151e6a87aae7c109ba9a0ed930ce4000"},
- {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2aae97087872ef152a0c40e06100b3665d8cb86b59bc8471ca7c26132fccd0f"},
- {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ac65eeec2250d03106b5e81284ad47f0d417ca299a45e89ccc69e36130ca8bc7"},
- {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a5346d08f3f4a6e9e672187faa179c7bf9227897081d7121866358af369f44f9"},
- {file = "pendulum-3.0.0-cp37-none-win_amd64.whl", hash = "sha256:235d64e87946d8f95c796af34818c76e0f88c94d624c268693c85b723b698aa9"},
- {file = "pendulum-3.0.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:6a881d9c2a7f85bc9adafcfe671df5207f51f5715ae61f5d838b77a1356e8b7b"},
- {file = "pendulum-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7762d2076b9b1cb718a6631ad6c16c23fc3fac76cbb8c454e81e80be98daa34"},
- {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e8e36a8130819d97a479a0e7bf379b66b3b1b520e5dc46bd7eb14634338df8c"},
- {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7dc843253ac373358ffc0711960e2dd5b94ab67530a3e204d85c6e8cb2c5fa10"},
- {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a78ad3635d609ceb1e97d6aedef6a6a6f93433ddb2312888e668365908c7120"},
- {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a137e9e0d1f751e60e67d11fc67781a572db76b2296f7b4d44554761049d6"},
- {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c95984037987f4a457bb760455d9ca80467be792236b69d0084f228a8ada0162"},
- {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d29c6e578fe0f893766c0d286adbf0b3c726a4e2341eba0917ec79c50274ec16"},
- {file = "pendulum-3.0.0-cp38-none-win_amd64.whl", hash = "sha256:deaba8e16dbfcb3d7a6b5fabdd5a38b7c982809567479987b9c89572df62e027"},
- {file = "pendulum-3.0.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b11aceea5b20b4b5382962b321dbc354af0defe35daa84e9ff3aae3c230df694"},
- {file = "pendulum-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a90d4d504e82ad236afac9adca4d6a19e4865f717034fc69bafb112c320dcc8f"},
- {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:825799c6b66e3734227756fa746cc34b3549c48693325b8b9f823cb7d21b19ac"},
- {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad769e98dc07972e24afe0cff8d365cb6f0ebc7e65620aa1976fcfbcadc4c6f3"},
- {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6fc26907eb5fb8cc6188cc620bc2075a6c534d981a2f045daa5f79dfe50d512"},
- {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c717eab1b6d898c00a3e0fa7781d615b5c5136bbd40abe82be100bb06df7a56"},
- {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3ddd1d66d1a714ce43acfe337190be055cdc221d911fc886d5a3aae28e14b76d"},
- {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:822172853d7a9cf6da95d7b66a16c7160cb99ae6df55d44373888181d7a06edc"},
- {file = "pendulum-3.0.0-cp39-none-win_amd64.whl", hash = "sha256:840de1b49cf1ec54c225a2a6f4f0784d50bd47f68e41dc005b7f67c7d5b5f3ae"},
- {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3b1f74d1e6ffe5d01d6023870e2ce5c2191486928823196f8575dcc786e107b1"},
- {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:729e9f93756a2cdfa77d0fc82068346e9731c7e884097160603872686e570f07"},
- {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e586acc0b450cd21cbf0db6bae386237011b75260a3adceddc4be15334689a9a"},
- {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7944ffc1f0099a79ff468ee9630c73f8c7835cd76fdb57ef7320e6a409df4"},
- {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fa30af36bd8e50686846bdace37cf6707bdd044e5cb6e1109acbad3277232e04"},
- {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:440215347b11914ae707981b9a57ab9c7b6983ab0babde07063c6ee75c0dc6e7"},
- {file = "pendulum-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:314c4038dc5e6a52991570f50edb2f08c339debdf8cea68ac355b32c4174e820"},
- {file = "pendulum-3.0.0-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5acb1d386337415f74f4d1955c4ce8d0201978c162927d07df8eb0692b2d8533"},
- {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a789e12fbdefaffb7b8ac67f9d8f22ba17a3050ceaaa635cd1cc4645773a4b1e"},
- {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860aa9b8a888e5913bd70d819306749e5eb488e6b99cd6c47beb701b22bdecf5"},
- {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5ebc65ea033ef0281368217fbf59f5cb05b338ac4dd23d60959c7afcd79a60a0"},
- {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d9fef18ab0386ef6a9ac7bad7e43ded42c83ff7ad412f950633854f90d59afa8"},
- {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c134ba2f0571d0b68b83f6972e2307a55a5a849e7dac8505c715c531d2a8795"},
- {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:385680812e7e18af200bb9b4a49777418c32422d05ad5a8eb85144c4a285907b"},
- {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eec91cd87c59fb32ec49eb722f375bd58f4be790cae11c1b70fac3ee4f00da0"},
- {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4386bffeca23c4b69ad50a36211f75b35a4deb6210bdca112ac3043deb7e494a"},
- {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dfbcf1661d7146d7698da4b86e7f04814221081e9fe154183e34f4c5f5fa3bf8"},
- {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:04a1094a5aa1daa34a6b57c865b25f691848c61583fb22722a4df5699f6bf74c"},
- {file = "pendulum-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5b0ec85b9045bd49dd3a3493a5e7ddfd31c36a2a60da387c419fa04abcaecb23"},
- {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0a15b90129765b705eb2039062a6daf4d22c4e28d1a54fa260892e8c3ae6e157"},
- {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:bb8f6d7acd67a67d6fedd361ad2958ff0539445ef51cbe8cd288db4306503cd0"},
- {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd69b15374bef7e4b4440612915315cc42e8575fcda2a3d7586a0d88192d0c88"},
- {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc00f8110db6898360c53c812872662e077eaf9c75515d53ecc65d886eec209a"},
- {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:83a44e8b40655d0ba565a5c3d1365d27e3e6778ae2a05b69124db9e471255c4a"},
- {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1a3604e9fbc06b788041b2a8b78f75c243021e0f512447806a6d37ee5214905d"},
- {file = "pendulum-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:92c307ae7accebd06cbae4729f0ba9fa724df5f7d91a0964b1b972a22baa482b"},
- {file = "pendulum-3.0.0.tar.gz", hash = "sha256:5d034998dea404ec31fae27af6b22cff1708f830a1ed7353be4d1019bb9f584e"},
-]
-
-[package.dependencies]
-python-dateutil = ">=2.6"
-tzdata = ">=2020.1"
-
-[package.extras]
-test = ["time-machine (>=2.6.0)"]
-
-[[package]]
-name = "pexpect"
-version = "4.9.0"
-description = "Pexpect allows easy control of interactive console applications."
-optional = false
-python-versions = "*"
-files = [
- {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"},
- {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
-]
-
-[package.dependencies]
-ptyprocess = ">=0.5"
-
-[[package]]
-name = "platformdirs"
-version = "4.2.2"
-description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
- {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
-]
-
-[package.extras]
-docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
-test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
-type = ["mypy (>=1.8)"]
-
-[[package]]
-name = "pluggy"
-version = "1.5.0"
-description = "plugin and hook calling mechanisms for python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
- {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
-]
-
-[package.extras]
-dev = ["pre-commit", "tox"]
-testing = ["pytest", "pytest-benchmark"]
-
-[[package]]
-name = "pprintpp"
-version = "0.4.0"
-description = "A drop-in replacement for pprint that's actually pretty"
-optional = false
-python-versions = "*"
-files = [
- {file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"},
- {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"},
-]
-
-[[package]]
-name = "pre-commit"
-version = "2.21.0"
-description = "A framework for managing and maintaining multi-language pre-commit hooks."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"},
- {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"},
-]
-
-[package.dependencies]
-cfgv = ">=2.0.0"
-identify = ">=1.0.0"
-nodeenv = ">=0.11.1"
-pyyaml = ">=5.1"
-virtualenv = ">=20.10.0"
-
-[[package]]
-name = "prompt-toolkit"
-version = "3.0.47"
-description = "Library for building powerful interactive command lines in Python"
-optional = false
-python-versions = ">=3.7.0"
-files = [
- {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"},
- {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"},
-]
-
-[package.dependencies]
-wcwidth = "*"
-
-[[package]]
-name = "ptyprocess"
-version = "0.7.0"
-description = "Run a subprocess in a pseudo terminal"
-optional = false
-python-versions = "*"
-files = [
- {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
- {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
-]
-
-[[package]]
-name = "pure-eval"
-version = "0.2.2"
-description = "Safely evaluate AST nodes without side effects"
-optional = false
-python-versions = "*"
-files = [
- {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"},
- {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"},
-]
-
-[package.extras]
-tests = ["pytest"]
-
-[[package]]
-name = "pyarrow"
-version = "14.0.2"
-description = "Python library for Apache Arrow"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pyarrow-14.0.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:ba9fe808596c5dbd08b3aeffe901e5f81095baaa28e7d5118e01354c64f22807"},
- {file = "pyarrow-14.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:22a768987a16bb46220cef490c56c671993fbee8fd0475febac0b3e16b00a10e"},
- {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dbba05e98f247f17e64303eb876f4a80fcd32f73c7e9ad975a83834d81f3fda"},
- {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a898d134d00b1eca04998e9d286e19653f9d0fcb99587310cd10270907452a6b"},
- {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:87e879323f256cb04267bb365add7208f302df942eb943c93a9dfeb8f44840b1"},
- {file = "pyarrow-14.0.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:76fc257559404ea5f1306ea9a3ff0541bf996ff3f7b9209fc517b5e83811fa8e"},
- {file = "pyarrow-14.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0c4a18e00f3a32398a7f31da47fefcd7a927545b396e1f15d0c85c2f2c778cd"},
- {file = "pyarrow-14.0.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:87482af32e5a0c0cce2d12eb3c039dd1d853bd905b04f3f953f147c7a196915b"},
- {file = "pyarrow-14.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:059bd8f12a70519e46cd64e1ba40e97eae55e0cbe1695edd95384653d7626b23"},
- {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f16111f9ab27e60b391c5f6d197510e3ad6654e73857b4e394861fc79c37200"},
- {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06ff1264fe4448e8d02073f5ce45a9f934c0f3db0a04460d0b01ff28befc3696"},
- {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6dd4f4b472ccf4042f1eab77e6c8bce574543f54d2135c7e396f413046397d5a"},
- {file = "pyarrow-14.0.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:32356bfb58b36059773f49e4e214996888eeea3a08893e7dbde44753799b2a02"},
- {file = "pyarrow-14.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:52809ee69d4dbf2241c0e4366d949ba035cbcf48409bf404f071f624ed313a2b"},
- {file = "pyarrow-14.0.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:c87824a5ac52be210d32906c715f4ed7053d0180c1060ae3ff9b7e560f53f944"},
- {file = "pyarrow-14.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a25eb2421a58e861f6ca91f43339d215476f4fe159eca603c55950c14f378cc5"},
- {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c1da70d668af5620b8ba0a23f229030a4cd6c5f24a616a146f30d2386fec422"},
- {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cc61593c8e66194c7cdfae594503e91b926a228fba40b5cf25cc593563bcd07"},
- {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:78ea56f62fb7c0ae8ecb9afdd7893e3a7dbeb0b04106f5c08dbb23f9c0157591"},
- {file = "pyarrow-14.0.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:37c233ddbce0c67a76c0985612fef27c0c92aef9413cf5aa56952f359fcb7379"},
- {file = "pyarrow-14.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:e4b123ad0f6add92de898214d404e488167b87b5dd86e9a434126bc2b7a5578d"},
- {file = "pyarrow-14.0.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:e354fba8490de258be7687f341bc04aba181fc8aa1f71e4584f9890d9cb2dec2"},
- {file = "pyarrow-14.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:20e003a23a13da963f43e2b432483fdd8c38dc8882cd145f09f21792e1cf22a1"},
- {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc0de7575e841f1595ac07e5bc631084fd06ca8b03c0f2ecece733d23cd5102a"},
- {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e986dc859712acb0bd45601229021f3ffcdfc49044b64c6d071aaf4fa49e98"},
- {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:f7d029f20ef56673a9730766023459ece397a05001f4e4d13805111d7c2108c0"},
- {file = "pyarrow-14.0.2-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:209bac546942b0d8edc8debda248364f7f668e4aad4741bae58e67d40e5fcf75"},
- {file = "pyarrow-14.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:1e6987c5274fb87d66bb36816afb6f65707546b3c45c44c28e3c4133c010a881"},
- {file = "pyarrow-14.0.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:a01d0052d2a294a5f56cc1862933014e696aa08cc7b620e8c0cce5a5d362e976"},
- {file = "pyarrow-14.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a51fee3a7db4d37f8cda3ea96f32530620d43b0489d169b285d774da48ca9785"},
- {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64df2bf1ef2ef14cee531e2dfe03dd924017650ffaa6f9513d7a1bb291e59c15"},
- {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c0fa3bfdb0305ffe09810f9d3e2e50a2787e3a07063001dcd7adae0cee3601a"},
- {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c65bf4fd06584f058420238bc47a316e80dda01ec0dfb3044594128a6c2db794"},
- {file = "pyarrow-14.0.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:63ac901baec9369d6aae1cbe6cca11178fb018a8d45068aaf5bb54f94804a866"},
- {file = "pyarrow-14.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:75ee0efe7a87a687ae303d63037d08a48ef9ea0127064df18267252cfe2e9541"},
- {file = "pyarrow-14.0.2.tar.gz", hash = "sha256:36cef6ba12b499d864d1def3e990f97949e0b79400d08b7cf74504ffbd3eb025"},
-]
-
-[package.dependencies]
-numpy = ">=1.16.6"
-
-[[package]]
-name = "pydantic"
-version = "2.7.4"
-description = "Data validation using Python type hints"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"},
- {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"},
-]
-
-[package.dependencies]
-annotated-types = ">=0.4.0"
-pydantic-core = "2.18.4"
-typing-extensions = ">=4.6.1"
-
-[package.extras]
-email = ["email-validator (>=2.0.0)"]
-
-[[package]]
-name = "pydantic-core"
-version = "2.18.4"
-description = "Core functionality for Pydantic validation and serialization"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"},
- {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"},
- {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"},
- {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"},
- {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"},
- {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"},
- {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"},
- {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"},
- {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"},
- {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"},
- {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"},
- {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"},
- {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"},
- {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"},
- {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"},
- {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"},
- {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"},
- {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"},
- {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"},
- {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"},
- {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"},
- {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"},
- {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"},
- {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"},
- {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"},
- {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"},
- {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"},
- {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"},
- {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"},
- {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"},
- {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"},
- {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"},
- {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"},
- {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"},
- {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"},
- {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"},
- {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"},
- {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"},
- {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"},
- {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"},
- {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"},
- {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"},
- {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"},
- {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"},
- {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"},
- {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"},
- {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"},
- {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"},
- {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"},
- {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"},
- {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"},
- {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"},
- {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"},
- {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"},
- {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"},
- {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"},
- {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"},
- {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"},
- {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"},
- {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"},
- {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"},
- {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"},
- {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"},
- {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"},
- {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"},
-]
-
-[package.dependencies]
-typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
-
-[[package]]
-name = "pydantic-settings"
-version = "2.4.0"
-description = "Settings management using Pydantic"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pydantic_settings-2.4.0-py3-none-any.whl", hash = "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315"},
- {file = "pydantic_settings-2.4.0.tar.gz", hash = "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88"},
-]
-
-[package.dependencies]
-pydantic = ">=2.7.0"
-python-dotenv = ">=0.21.0"
-
-[package.extras]
-azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"]
-toml = ["tomli (>=2.0.1)"]
-yaml = ["pyyaml (>=6.0.1)"]
-
-[[package]]
-name = "pygments"
-version = "2.18.0"
-description = "Pygments is a syntax highlighting package written in Python."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
- {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
-]
-
-[package.extras]
-windows-terminal = ["colorama (>=0.4.6)"]
-
-[[package]]
-name = "pylint"
-version = "3.2.3"
-description = "python code static checker"
-optional = false
-python-versions = ">=3.8.0"
-files = [
- {file = "pylint-3.2.3-py3-none-any.whl", hash = "sha256:b3d7d2708a3e04b4679e02d99e72329a8b7ee8afb8d04110682278781f889fa8"},
- {file = "pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60"},
-]
-
-[package.dependencies]
-astroid = ">=3.2.2,<=3.3.0-dev0"
-colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
-dill = [
- {version = ">=0.2", markers = "python_version < \"3.11\""},
- {version = ">=0.3.7", markers = "python_version >= \"3.12\""},
- {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
-]
-isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
-mccabe = ">=0.6,<0.8"
-platformdirs = ">=2.2.0"
-tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-tomlkit = ">=0.10.1"
-typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
-
-[package.extras]
-spelling = ["pyenchant (>=3.2,<4.0)"]
-testutils = ["gitpython (>3)"]
-
-[[package]]
-name = "pytest"
-version = "8.2.2"
-description = "pytest: simple powerful testing with Python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
- {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "sys_platform == \"win32\""}
-exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
-iniconfig = "*"
-packaging = "*"
-pluggy = ">=1.5,<2.0"
-tomli = {version = ">=1", markers = "python_version < \"3.11\""}
-
-[package.extras]
-dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
-
-[[package]]
-name = "pytest-asyncio"
-version = "0.23.7"
-description = "Pytest support for asyncio"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"},
- {file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"},
-]
-
-[package.dependencies]
-pytest = ">=7.0.0,<9"
-
-[package.extras]
-docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
-testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
-
-[[package]]
-name = "pytest-clarity"
-version = "1.0.1"
-description = "A plugin providing an alternative, colourful diff output for failing assertions."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
- {file = "pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772"},
-]
-
-[package.dependencies]
-pprintpp = ">=0.4.0"
-pytest = ">=3.5.0"
-rich = ">=8.0.0"
-
-[[package]]
-name = "pytest-cov"
-version = "4.1.0"
-description = "Pytest plugin for measuring coverage."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"},
- {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"},
-]
-
-[package.dependencies]
-coverage = {version = ">=5.2.1", extras = ["toml"]}
-pytest = ">=4.6"
-
-[package.extras]
-testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
-
-[[package]]
-name = "pytest-httpx"
-version = "0.30.0"
-description = "Send responses to httpx."
-optional = false
-python-versions = ">=3.9"
-files = [
- {file = "pytest-httpx-0.30.0.tar.gz", hash = "sha256:755b8edca87c974dd4f3605c374fda11db84631de3d163b99c0df5807023a19a"},
- {file = "pytest_httpx-0.30.0-py3-none-any.whl", hash = "sha256:6d47849691faf11d2532565d0c8e0e02b9f4ee730da31687feae315581d7520c"},
-]
-
-[package.dependencies]
-httpx = "==0.27.*"
-pytest = ">=7,<9"
-
-[package.extras]
-testing = ["pytest-asyncio (==0.23.*)", "pytest-cov (==4.*)"]
-
-[[package]]
-name = "pytest-xdist"
-version = "3.6.1"
-description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"},
- {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"},
-]
-
-[package.dependencies]
-execnet = ">=2.1"
-pytest = ">=7.0.0"
-
-[package.extras]
-psutil = ["psutil (>=3.0)"]
-setproctitle = ["setproctitle"]
-testing = ["filelock"]
-
-[[package]]
-name = "python-dateutil"
-version = "2.9.0.post0"
-description = "Extensions to the standard Python datetime module"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-files = [
- {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
- {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
-]
-
-[package.dependencies]
-six = ">=1.5"
-
-[[package]]
-name = "python-dotenv"
-version = "1.0.1"
-description = "Read key-value pairs from a .env file and set them as environment variables"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
- {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
-]
-
-[package.extras]
-cli = ["click (>=5.0)"]
-
-[[package]]
-name = "pyyaml"
-version = "6.0.1"
-description = "YAML parser and emitter for Python"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
- {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
- {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
- {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
- {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
- {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
- {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
- {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
- {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
- {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
- {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
- {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
- {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
- {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
- {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
- {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
- {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
- {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
- {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
- {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
- {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
- {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
- {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
- {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
- {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
- {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
- {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
- {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
- {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
- {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
- {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
- {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
- {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
- {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
- {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
- {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
- {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
- {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
- {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
- {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
- {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
- {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
- {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
- {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
- {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
- {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
- {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
- {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
- {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
- {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
- {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
-]
-
-[[package]]
-name = "redis"
-version = "4.6.0"
-description = "Python client for Redis database and key-value store"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "redis-4.6.0-py3-none-any.whl", hash = "sha256:e2b03db868160ee4591de3cb90d40ebb50a90dd302138775937f6a42b7ed183c"},
- {file = "redis-4.6.0.tar.gz", hash = "sha256:585dc516b9eb042a619ef0a39c3d7d55fe81bdb4df09a52c9cdde0d07bf1aa7d"},
-]
-
-[package.dependencies]
-async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""}
-
-[package.extras]
-hiredis = ["hiredis (>=1.0.0)"]
-ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"]
-
-[[package]]
-name = "requests"
-version = "2.32.3"
-description = "Python HTTP for Humans."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
- {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
-]
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<4"
-idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<3"
-
-[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
-
-[[package]]
-name = "rich"
-version = "13.7.1"
-description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
-optional = false
-python-versions = ">=3.7.0"
-files = [
- {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
- {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
-]
-
-[package.dependencies]
-markdown-it-py = ">=2.2.0"
-pygments = ">=2.13.0,<3.0.0"
-
-[package.extras]
-jupyter = ["ipywidgets (>=7.5.1,<9)"]
-
-[[package]]
-name = "ruff"
-version = "0.5.0"
-description = "An extremely fast Python linter and code formatter, written in Rust."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "ruff-0.5.0-py3-none-linux_armv6l.whl", hash = "sha256:ee770ea8ab38918f34e7560a597cc0a8c9a193aaa01bfbd879ef43cb06bd9c4c"},
- {file = "ruff-0.5.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38f3b8327b3cb43474559d435f5fa65dacf723351c159ed0dc567f7ab735d1b6"},
- {file = "ruff-0.5.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7594f8df5404a5c5c8f64b8311169879f6cf42142da644c7e0ba3c3f14130370"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adc7012d6ec85032bc4e9065110df205752d64010bed5f958d25dbee9ce35de3"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d505fb93b0fabef974b168d9b27c3960714d2ecda24b6ffa6a87ac432905ea38"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dc5cfd3558f14513ed0d5b70ce531e28ea81a8a3b1b07f0f48421a3d9e7d80a"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:db3ca35265de239a1176d56a464b51557fce41095c37d6c406e658cf80bbb362"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b1a321c4f68809fddd9b282fab6a8d8db796b270fff44722589a8b946925a2a8"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c4dfcd8d34b143916994b3876b63d53f56724c03f8c1a33a253b7b1e6bf2a7d"},
- {file = "ruff-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81e5facfc9f4a674c6a78c64d38becfbd5e4f739c31fcd9ce44c849f1fad9e4c"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e589e27971c2a3efff3fadafb16e5aef7ff93250f0134ec4b52052b673cf988d"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2ffbc3715a52b037bcb0f6ff524a9367f642cdc5817944f6af5479bbb2eb50e"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cd096e23c6a4f9c819525a437fa0a99d1c67a1b6bb30948d46f33afbc53596cf"},
- {file = "ruff-0.5.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:46e193b36f2255729ad34a49c9a997d506e58f08555366b2108783b3064a0e1e"},
- {file = "ruff-0.5.0-py3-none-win32.whl", hash = "sha256:49141d267100f5ceff541b4e06552e98527870eafa1acc9dec9139c9ec5af64c"},
- {file = "ruff-0.5.0-py3-none-win_amd64.whl", hash = "sha256:e9118f60091047444c1b90952736ee7b1792910cab56e9b9a9ac20af94cd0440"},
- {file = "ruff-0.5.0-py3-none-win_arm64.whl", hash = "sha256:ed5c4df5c1fb4518abcb57725b576659542bdbe93366f4f329e8f398c4b71178"},
- {file = "ruff-0.5.0.tar.gz", hash = "sha256:eb641b5873492cf9bd45bc9c5ae5320648218e04386a5f0c264ad6ccce8226a1"},
-]
-
-[[package]]
-name = "shellingham"
-version = "1.5.4"
-description = "Tool to Detect Surrounding Shell"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
- {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
-]
-
-[[package]]
-name = "six"
-version = "1.16.0"
-description = "Python 2 and 3 compatibility utilities"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-files = [
- {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
- {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
-]
-
-[[package]]
-name = "smmap"
-version = "5.0.1"
-description = "A pure Python implementation of a sliding window memory map manager"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"},
- {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"},
-]
-
-[[package]]
-name = "sniffio"
-version = "1.3.1"
-description = "Sniff out which async library your code is running under"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
- {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
-]
-
-[[package]]
-name = "stack-data"
-version = "0.6.3"
-description = "Extract data from python stack frames and tracebacks for informative displays"
-optional = false
-python-versions = "*"
-files = [
- {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"},
- {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"},
-]
-
-[package.dependencies]
-asttokens = ">=2.1.0"
-executing = ">=1.2.0"
-pure-eval = "*"
-
-[package.extras]
-tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
-
-[[package]]
-name = "structlog"
-version = "22.3.0"
-description = "Structured Logging for Python"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "structlog-22.3.0-py3-none-any.whl", hash = "sha256:b403f344f902b220648fa9f286a23c0cc5439a5844d271fec40562dbadbc70ad"},
- {file = "structlog-22.3.0.tar.gz", hash = "sha256:e7509391f215e4afb88b1b80fa3ea074be57a5a17d794bd436a5c949da023333"},
-]
-
-[package.extras]
-dev = ["structlog[docs,tests,typing]"]
-docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted"]
-tests = ["coverage[toml]", "freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"]
-typing = ["mypy", "rich", "twisted"]
-
-[[package]]
-name = "toml"
-version = "0.10.2"
-description = "Python Library for Tom's Obvious, Minimal Language"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-files = [
- {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
- {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
-]
-
-[[package]]
-name = "tomli"
-version = "2.0.1"
-description = "A lil' TOML parser"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
- {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
-]
-
-[[package]]
-name = "tomlkit"
-version = "0.12.5"
-description = "Style preserving TOML library"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"},
- {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"},
-]
-
-[[package]]
-name = "tqdm"
-version = "4.66.5"
-description = "Fast, Extensible Progress Meter"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"},
- {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "platform_system == \"Windows\""}
-
-[package.extras]
-dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"]
-notebook = ["ipywidgets (>=6)"]
-slack = ["slack-sdk"]
-telegram = ["requests"]
-
-[[package]]
-name = "traitlets"
-version = "5.14.3"
-description = "Traitlets Python configuration system"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"},
- {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"},
-]
-
-[package.extras]
-docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"]
-test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"]
-
-[[package]]
-name = "typer"
-version = "0.12.3"
-description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"},
- {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"},
-]
-
-[package.dependencies]
-click = ">=8.0.0"
-rich = ">=10.11.0"
-shellingham = ">=1.3.0"
-typing-extensions = ">=3.7.4.3"
-
-[[package]]
-name = "typer-cli"
-version = "0.12.3"
-description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "typer_cli-0.12.3-py3-none-any.whl", hash = "sha256:33ee23585e3013804354e0db21b06880960056c6a52012bdaba62dbf6e9e46ed"},
- {file = "typer_cli-0.12.3.tar.gz", hash = "sha256:1f66684489ea15b08f613d76948c4f99d6b69c69de47010bbc0032d9de4d45b5"},
-]
-
-[package.dependencies]
-typer = "0.12.3"
-
-[[package]]
-name = "types-python-slugify"
-version = "8.0.2.20240310"
-description = "Typing stubs for python-slugify"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "types-python-slugify-8.0.2.20240310.tar.gz", hash = "sha256:5157b508c7fed587520c70d77f62aea0fafdc6620893c2ec8972f13a1faf5560"},
- {file = "types_python_slugify-8.0.2.20240310-py3-none-any.whl", hash = "sha256:0efec18b802c69ebd22dcee55c91afaeaa80e1e40ddd66ccabf69fd42ce87b74"},
-]
-
-[[package]]
-name = "types-pyyaml"
-version = "6.0.12.20240311"
-description = "Typing stubs for PyYAML"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "types-PyYAML-6.0.12.20240311.tar.gz", hash = "sha256:a9e0f0f88dc835739b0c1ca51ee90d04ca2a897a71af79de9aec5f38cb0a5342"},
- {file = "types_PyYAML-6.0.12.20240311-py3-none-any.whl", hash = "sha256:b845b06a1c7e54b8e5b4c683043de0d9caf205e7434b3edc678ff2411979b8f6"},
-]
-
-[[package]]
-name = "types-toml"
-version = "0.10.8.20240310"
-description = "Typing stubs for toml"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "types-toml-0.10.8.20240310.tar.gz", hash = "sha256:3d41501302972436a6b8b239c850b26689657e25281b48ff0ec06345b8830331"},
- {file = "types_toml-0.10.8.20240310-py3-none-any.whl", hash = "sha256:627b47775d25fa29977d9c70dc0cbab3f314f32c8d8d0c012f2ef5de7aaec05d"},
-]
-
-[[package]]
-name = "types-ujson"
-version = "5.10.0.20240515"
-description = "Typing stubs for ujson"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "types-ujson-5.10.0.20240515.tar.gz", hash = "sha256:ceae7127f0dafe4af5dd0ecf98ee13e9d75951ef963b5c5a9b7ea92e0d71f0d7"},
- {file = "types_ujson-5.10.0.20240515-py3-none-any.whl", hash = "sha256:02bafc36b3a93d2511757a64ff88bd505e0a57fba08183a9150fbcfcb2015310"},
-]
-
-[[package]]
-name = "typing-extensions"
-version = "4.12.2"
-description = "Backported and Experimental Type Hints for Python 3.8+"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
- {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
-]
-
-[[package]]
-name = "tzdata"
-version = "2024.1"
-description = "Provider of IANA time zone data"
-optional = false
-python-versions = ">=2"
-files = [
- {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
- {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
-]
-
-[[package]]
-name = "ujson"
-version = "5.10.0"
-description = "Ultra fast JSON encoder and decoder for Python"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"},
- {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"},
- {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"},
- {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"},
- {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"},
- {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"},
- {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"},
- {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"},
- {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"},
- {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"},
- {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"},
- {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"},
- {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"},
- {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"},
- {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"},
- {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"},
- {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"},
- {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"},
- {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"},
- {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"},
- {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"},
- {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"},
- {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"},
- {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"},
- {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"},
- {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"},
- {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"},
- {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"},
- {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"},
- {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"},
- {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"},
- {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"},
- {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"},
- {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"},
- {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"},
- {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"},
- {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"},
- {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"},
- {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"},
- {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"},
- {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"},
- {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"},
- {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"},
- {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"},
- {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"},
- {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"},
- {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"},
- {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"},
- {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"},
- {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"},
- {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"},
- {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"},
- {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"},
- {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"},
- {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"},
- {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"},
- {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"},
- {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"},
- {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"},
- {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"},
- {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"},
- {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"},
- {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"},
- {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"},
-]
-
-[[package]]
-name = "urllib3"
-version = "2.2.2"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
- {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
-]
-
-[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
-h2 = ["h2 (>=4,<5)"]
-socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
-zstd = ["zstandard (>=0.18.0)"]
-
-[[package]]
-name = "virtualenv"
-version = "20.26.2"
-description = "Virtual Python Environment builder"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"},
- {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"},
-]
-
-[package.dependencies]
-distlib = ">=0.3.7,<1"
-filelock = ">=3.12.2,<4"
-platformdirs = ">=3.9.1,<5"
-
-[package.extras]
-docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
-test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
-
-[[package]]
-name = "wcwidth"
-version = "0.2.13"
-description = "Measures the displayed width of unicode strings in a terminal"
-optional = false
-python-versions = "*"
-files = [
- {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
- {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
-]
-
-[[package]]
-name = "yamllint"
-version = "1.35.1"
-description = "A linter for YAML files."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "yamllint-1.35.1-py3-none-any.whl", hash = "sha256:2e16e504bb129ff515b37823b472750b36b6de07963bd74b307341ef5ad8bdc3"},
- {file = "yamllint-1.35.1.tar.gz", hash = "sha256:7a003809f88324fd2c877734f2d575ee7881dd9043360657cc8049c809eba6cd"},
-]
-
-[package.dependencies]
-pathspec = ">=0.5.3"
-pyyaml = "*"
-
-[package.extras]
-dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"]
-
-[metadata]
-lock-version = "2.0"
-python-versions = ">=3.9, < 3.13"
-content-hash = "83deb599bdfd22feb32ca5971f96380738a59ac5df19f4e11c6688d7080b3616"
diff --git a/sync/potenda/potenda/__init__.py b/sync/potenda/potenda/__init__.py
deleted file mode 100644
index efd25e81a0..0000000000
--- a/sync/potenda/potenda/__init__.py
+++ /dev/null
@@ -1,80 +0,0 @@
-from typing import List, Optional
-
-from tqdm import tqdm
-
-from diffsync import DiffSync
-from diffsync.diff import Diff
-from diffsync.enum import DiffSyncFlags
-from diffsync.logging import enable_console_logging
-from infrahub_sync import SyncInstance
-
-
-class Potenda:
- def __init__(
- self,
- source: DiffSync,
- destination: DiffSync,
- config: SyncInstance,
- top_level: List[str],
- partition=None,
- show_progress: Optional[bool] = False,
- ):
- self.top_level = top_level
-
- self.config = config
-
- self.source = source
- self.destination = destination
-
- self.source.top_level = top_level
- self.destination.top_level = top_level
-
- self.partition = partition
- self.progress_bar = None
- self.show_progress = show_progress
- enable_console_logging(verbosity=1)
- self.flags = DiffSyncFlags.SKIP_UNMATCHED_DST
-
- def _print_callback(self, stage: str, elements_processed: int, total_models: int):
- """Callback for DiffSync using tqdm"""
- if self.show_progress:
- if self.progress_bar is None:
- self.progress_bar = tqdm(total=total_models, desc=stage, unit="models")
-
- self.progress_bar.n = elements_processed
- self.progress_bar.refresh()
-
- if elements_processed == total_models:
- self.progress_bar.close()
- self.progress_bar = None
-
- def source_load(self):
- try:
- print(f"Load: Importing data from {self.source}")
- self.source.load()
- except Exception as exc:
- raise ValueError(f"An error occurred while loading {self.source}: {str(exc)}") from exc
-
- def destination_load(self):
- try:
- print(f"Load: Importing data from {self.destination}")
- self.destination.load()
- except Exception as exc:
- raise ValueError(f"An error occurred while loading {self.destination}: {str(exc)}") from exc
-
- def load(self):
- try:
- self.source_load()
- self.destination_load()
- except Exception as exc:
- raise ValueError(f"An error occurred while loading the sync: {str(exc)}") from exc
-
- def diff(self) -> Diff:
- print(f"Diff: Comparing data from {self.source} to {self.destination}")
- self.progress_bar = None
- return self.destination.diff_from(self.source, flags=self.flags, callback=self._print_callback)
-
- def sync(self, diff: Optional[Diff] = None):
- print(f"Sync: Importing data from {self.source} to {self.destination} based on Diff")
- self.progress_bar = None
- return self.destination.sync_from(self.source, diff=diff, flags=self.flags, callback=self._print_callback)
diff --git a/sync/pyproject.toml b/sync/pyproject.toml
deleted file mode 100644
index 9437075242..0000000000
--- a/sync/pyproject.toml
+++ /dev/null
@@ -1,238 +0,0 @@
-[tool.poetry]
-name = "infrahub-sync"
-version = "0.5.0"
-description = "Infrahub-Sync is a versatile Python package that synchronizes data between a source and a destination system"
-authors = ["OpsMill "]
-readme = "README.md"
-license = "Apache-2.0"
-homepage = "https://opsmill.com"
-repository = "https://github.com/opsmill/infrahub"
-documentation = "https://docs.infrahub.app/integrations/sync/"
-packages = [
- { include = "infrahub_sync", from = "infrahub-sync"},
- { include = "potenda", from = "potenda"},
-]
-classifiers = [
- "Intended Audience :: Developers",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
-]
-
-[tool.poetry.dependencies]
-python = ">=3.9, < 3.13"
-infrahub-sdk = {version = "^0,>=0.11", extras = ["all"]}
-structlog = "^22.3.0"
-diffsync = { version = ">=1.10,<2.0 || >=2.0", extras = ["redis"] }
-netutils = "^1.9.1"
-tqdm = "^4.66.5"
-
-[tool.poetry.group.dev.dependencies]
-pytest = "*"
-pytest-clarity = "^1.0.1"
-pytest-cov = "^4.0.0"
-pytest-httpx = "*"
-yamllint = "*"
-pylint = "*"
-mypy = "*"
-ipython = "*"
-pytest-asyncio = "*"
-requests = "*"
-pre-commit = "^2.20.0"
-types-toml = "*"
-types-ujson = "*"
-types-pyyaml = "*"
-typer-cli = "*"
-ruff = "0.5.0"
-pytest-xdist = "^3.3.1"
-types-python-slugify = "^8.0.0.3"
-
-[tool.poetry.scripts]
-infrahub-sync = "infrahub_sync.cli:app"
-
-[tool.coverage.run]
-branch = true
-
-[tool.coverage.report]
-exclude_lines = [
- "if TYPE_CHECKING:",
- "raise NotImplementedError()"
-]
-
-[tool.pylint.general]
-extension-pkg-whitelist = [
- "pydantic",
- "ujson",
-]
-
-[tool.pylint.format]
-disable = "logging-fstring-interpolation"
-
-[tool.pylint.basic]
-# No docstrings required for private methods (Pylint default), or for test_ functions.
-no-docstring-rgx="^(_|test_)"
-
-[tool.pylint.messages_control]
-# Line length is enforced by Black, so pylint doesn't need to check it.
-# Pylint and Black disagree about how to format multi-line arrays; Black wins.
-# assigning-non-slot,no-member,unsupported-membership-test,unsubscriptable-object,unsupported-assignment-operation,not-an-iterable
-# are disabled because of our move to pydantic 2, pylint does not seem to respect the type hint for pydantic 2 model fields.
-disable = """,
- line-too-long,
- missing-module-docstring,
- missing-function-docstring,
- missing-class-docstring,
- consider-using-from-import,
- invalid-name,
- too-many-arguments,
- too-many-locals,
- keyword-arg-before-vararg,
- too-few-public-methods,
- too-many-instance-attributes,
- fixme,
- consider-using-f-string,
- protected-access,
- import-self,
- wrong-import-order,
- assigning-non-slot,
- no-member,
- unsupported-membership-test,
- unsubscriptable-object,
- unsupported-assignment-operation,
- not-an-iterable,
- multiple-statements,
- """
-
-[tool.pylint.miscellaneous]
-notes = """,
- FIXME,
- XXX,
- """
-
-[tool.pylint.similarities]
-min-similarity-lines = 20
-
-[tool.pytest.ini_options]
-asyncio_mode = "auto"
-testpaths = [
- "tests"
-]
-filterwarnings = [
- "ignore:Module already imported so cannot be rewritten",
- "ignore:the imp module is deprecated",
- "ignore:Deprecated call to",
-]
-addopts = "-vs --cov-report term-missing --cov-report xml --dist loadscope"
-
-[tool.mypy]
-pretty = true
-ignore_missing_imports = true
-disallow_untyped_defs = true
-
-[tool.ruff]
-line-length = 120
-
-exclude = [
- ".git",
- ".tox",
- ".venv",
- "env",
- "_build",
- "build",
- "dist",
- "examples",
-]
-
-
-[tool.ruff.lint]
-preview = true
-
-task-tags = [
- "FIXME",
- "TODO",
- "XXX",
-]
-
-select = [
- "ANN", # flake8-annotations
- "ASYNC", # flake8-async
- "B", # flake8-bugbear
- "C4", # flake8-comprehensions
- "C90", # mccabe complexity
- "DJ", # flake8-django
- "DTZ", # flake8-datetimez
- "E", # pycodestyle errors
- "EXE", # flake8-executable
- "F", # pyflakes
- "I", # isort-like checks
- "ICN", # flake8-import-conventions
- "INP", # flake8-no-pep420
- "N", # pep8-naming
- "PERF", # Perflint
- "PIE", # flake8-pie
- "PL", # pylint
- "PTH", # flake8-use-pathlib
- "PYI", # flake8-pyi
- "Q", # flake8-quotes
- "RET", # flake8-return
- "S", # flake8-bandit
- "TCH", # flake8-type-checking
- "T10", # flake8-debugger
- "UP", # pyupgrade
- "W", # pycodestyle warnings
- "YTT", # flake8-2020
-]
-
-ignore = [
-
-##################################################################################################
-# The ignored rules below should be removed once the code has been updated, they are included #
-# like this so that we can reactivate them one by one. Alternatively ignored after further #
-# investigation if they are deemed to not make sense. #
-##################################################################################################
- "ANN001", # Missing type annotation for function argument
- "ANN002", # Missing type annotation for `*args`
- "ANN003", # Missing type annotation for `**kwargs`
- "ANN201", # Missing return type annotation for public function
- "ANN202", # Missing return type annotation for private function
- "ANN204", # Missing return type annotation for special method
- "ANN206", # Missing return type annotation for classmethod
- "ANN401", # Dynamically typed expressions (typing.Any) are disallowed
- "B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling
- "C416", # Unnecessary `list` comprehension (rewrite using `list()`)
- "INP001", # File is part of an implicit namespace package. Add an `__init__.py`.
- "PERF401", # Use a list comprehension to create a transformed list
- "PLR0912", # Too many branches
- "PLR0913", # Too many arguments in function definition
- "PLR0917", # Too many positional arguments
- "PLR1702", # Too many nested blocks
- "PLR6301", # Method could be a function, class method, or static method
- "RET504", # Unnecessary assignment to `ptd` before `return` statement
- "S701", # By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True`
-]
-
-#https://docs.astral.sh/ruff/formatter/black/
-[tool.ruff.format]
-quote-style = "double"
-indent-style = "space"
-skip-magic-trailing-comma = false
-line-ending = "auto"
-
-[tool.ruff.lint.isort]
-known-first-party = ["diffsync", "infrahub_sync", "potenda"]
-
-[tool.ruff.lint.pycodestyle]
-max-line-length = 150
-
-[tool.ruff.lint.mccabe]
-# Target max-complexity=10
-max-complexity = 17
-
-[tool.ruff.lint.per-file-ignores]
-
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
diff --git a/tasks/__init__.py b/tasks/__init__.py
index b901182e54..daf9233883 100644
--- a/tasks/__init__.py
+++ b/tasks/__init__.py
@@ -2,7 +2,8 @@
from invoke import Collection, Context, task
-from . import backend, demo, dev, docs, main, performance, schema, sdk, sync
+from . import backend, demo, dev, docs, main, performance, schema, sdk
+from .utils import ESCAPED_REPO_PATH
ns = Collection()
ns.add_collection(sdk)
@@ -13,11 +14,10 @@
ns.add_collection(demo)
ns.add_collection(main)
ns.add_collection(schema)
-ns.add_collection(sync)
@task
-def yamllint(context: Context):
+def yamllint(context: Context) -> None:
"""This will run yamllint to validate formatting of all yaml files."""
exec_cmd = "yamllint -s ."
@@ -25,21 +25,27 @@ def yamllint(context: Context):
@task(name="format")
-def format_all(context: Context):
+def format_all(context: Context) -> None:
main.format_all(context)
- sdk.format_all(context)
backend.format_all(context)
- sync.format_all(context)
@task(name="lint")
-def lint_all(context: Context):
+def lint_all(context: Context) -> None:
yamllint(context)
- sdk.lint(context)
backend.lint(context)
- sync.lint(context)
+
+
+@task
+def pull(context: Context) -> None:
+ """Pull the latest changes from Github and update the submodule to the proper commit."""
+ commands = ["git pull", "git submodule update"]
+ with context.cd(ESCAPED_REPO_PATH):
+ for command in commands:
+ context.run(command, pty=True)
ns.add_task(format_all)
ns.add_task(lint_all)
ns.add_task(yamllint)
+ns.add_task(pull)
diff --git a/tasks/backend.py b/tasks/backend.py
index e5fd07df8b..7e3cfe67a5 100644
--- a/tasks/backend.py
+++ b/tasks/backend.py
@@ -2,6 +2,7 @@
from typing import Any, Optional
from invoke import Context, task
+from invoke.runners import Result
from .shared import (
BUILD_NAME,
@@ -25,7 +26,7 @@
# ----------------------------------------------------------------------------
-def _format_ruff(context: Context):
+def _format_ruff(context: Context) -> None:
"""Run ruff to format all Python files."""
print(f" - [{NAMESPACE}] Format code with ruff")
@@ -36,7 +37,7 @@ def _format_ruff(context: Context):
@task(name="format")
-def format_all(context: Context):
+def format_all(context: Context) -> None:
"""This will run all formatter."""
_format_ruff(context)
@@ -48,11 +49,11 @@ def format_all(context: Context):
# Testing tasks
# ----------------------------------------------------------------------------
@task
-def ruff(context: Context, docker: bool = False):
+def ruff(context: Context, docker: bool = False) -> None:
"""Run ruff to check that Python files adherence to black standards."""
print(f" - [{NAMESPACE}] Check code with ruff")
- exec_cmd = f"ruff check --diff {MAIN_DIRECTORY} --config {REPO_BASE}/pyproject.toml"
+ exec_cmd = f"poetry run ruff check --diff {MAIN_DIRECTORY} --config {REPO_BASE}/pyproject.toml"
if docker:
compose_files_cmd = build_test_compose_files_cmd(database=False)
@@ -64,11 +65,11 @@ def ruff(context: Context, docker: bool = False):
@task
-def mypy(context: Context, docker: bool = False):
+def mypy(context: Context, docker: bool = False) -> None:
"""This will run mypy for the specified name and Python version."""
print(f" - [{NAMESPACE}] Check code with mypy")
- exec_cmd = f"mypy --show-error-codes {MAIN_DIRECTORY}"
+ exec_cmd = f"poetry run mypy --show-error-codes {MAIN_DIRECTORY}"
if docker:
compose_files_cmd = build_test_compose_files_cmd(database=False)
@@ -80,11 +81,11 @@ def mypy(context: Context, docker: bool = False):
@task
-def pylint(context: Context, docker: bool = False):
+def pylint(context: Context, docker: bool = False) -> None:
"""This will run pylint for the specified name and Python version."""
print(f" - [{NAMESPACE}] Check code with pylint")
- exec_cmd = f"pylint --ignore-paths {MAIN_DIRECTORY}/tests {MAIN_DIRECTORY}"
+ exec_cmd = f"poetry run pylint --ignore-paths {MAIN_DIRECTORY}/tests {MAIN_DIRECTORY}"
if docker:
compose_files_cmd = build_test_compose_files_cmd(database=False)
@@ -96,7 +97,7 @@ def pylint(context: Context, docker: bool = False):
@task
-def lint(context: Context, docker: bool = False):
+def lint(context: Context, docker: bool = False) -> None:
"""This will run all linter."""
ruff(context, docker=docker)
mypy(context, docker=docker)
@@ -106,19 +107,17 @@ def lint(context: Context, docker: bool = False):
@task(optional=["database"])
-def test_unit(context: Context, database: str = INFRAHUB_DATABASE):
+def test_unit(context: Context, database: str = INFRAHUB_DATABASE) -> Optional[Result]:
with context.cd(ESCAPED_REPO_PATH):
- compose_files_cmd = build_test_compose_files_cmd(database=database)
- base_cmd = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {build_test_envs()} infrahub-test"
- exec_cmd = f"pytest -n {NBR_WORKERS} -v --cov=infrahub {MAIN_DIRECTORY}/tests/unit"
+ exec_cmd = f"poetry run pytest -n {NBR_WORKERS} -v --cov=infrahub {MAIN_DIRECTORY}/tests/unit"
if database == "neo4j":
exec_cmd += " --neo4j"
- print(f"{base_cmd} {exec_cmd}")
- return execute_command(context=context, command=f"{base_cmd} {exec_cmd}")
+ print(f"{exec_cmd}")
+ return execute_command(context=context, command=f"{exec_cmd}")
@task(optional=["database"])
-def test_core(context: Context, database: str = INFRAHUB_DATABASE):
+def test_core(context: Context, database: str = INFRAHUB_DATABASE) -> Optional[Result]:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_test_compose_files_cmd(database=database)
base_cmd = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {build_test_envs()} infrahub-test"
@@ -130,19 +129,19 @@ def test_core(context: Context, database: str = INFRAHUB_DATABASE):
@task(optional=["database"])
-def test_integration(context: Context, database: str = INFRAHUB_DATABASE):
+def test_integration(context: Context, database: str = INFRAHUB_DATABASE) -> Optional[Result]:
with context.cd(ESCAPED_REPO_PATH):
- compose_files_cmd = build_test_compose_files_cmd(database=database)
- base_cmd = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {build_test_envs()} infrahub-test"
- exec_cmd = f"pytest -n {NBR_WORKERS} -v --cov=infrahub {MAIN_DIRECTORY}/tests/integration"
+ exec_cmd = f"poetry run pytest -n {NBR_WORKERS} -v --cov=infrahub {MAIN_DIRECTORY}/tests/integration"
if database == "neo4j":
exec_cmd += " --neo4j"
- print(f"{base_cmd} {exec_cmd}")
- return execute_command(context=context, command=f"{base_cmd} {exec_cmd}")
+ print(f"{exec_cmd=}")
+ return execute_command(context=context, command=f"{exec_cmd}")
@task
-def test_scale_env_start(context: Context, database: str = INFRAHUB_DATABASE, gunicorn_workers: int = 4):
+def test_scale_env_start(
+ context: Context, database: str = INFRAHUB_DATABASE, gunicorn_workers: int = 4
+) -> Optional[Result]:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_test_scale_compose_files_cmd(database=database)
command = f"{get_env_vars(context)} GUNICORN_WORKERS={gunicorn_workers} docker compose {compose_files_cmd} -p {BUILD_NAME} up -d"
@@ -150,7 +149,7 @@ def test_scale_env_start(context: Context, database: str = INFRAHUB_DATABASE, gu
@task
-def test_scale_env_destroy(context: Context, database: str = INFRAHUB_DATABASE):
+def test_scale_env_destroy(context: Context, database: str = INFRAHUB_DATABASE) -> Optional[Result]:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_test_scale_compose_files_cmd(database=database)
command = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} down --remove-orphans --volumes"
@@ -161,13 +160,13 @@ def test_scale_env_destroy(context: Context, database: str = INFRAHUB_DATABASE):
def test_scale(
context: Context,
schema: Path = f"{ESCAPED_REPO_PATH}/backend/tests/scale/schema.yml",
- stager: str = None,
- amount: int = None,
- test: str = None,
- attrs: int = None,
- rels: int = None,
- changes: int = None,
-):
+ stager: Optional[str] = None,
+ amount: Optional[int] = None,
+ test: Optional[str] = None,
+ attrs: Optional[int] = None,
+ rels: Optional[int] = None,
+ changes: Optional[int] = None,
+) -> Optional[Result]:
args = []
if stager:
args.extend(["--stager", stager])
@@ -198,7 +197,7 @@ def test_scale(
@task(default=True)
-def format_and_lint(context: Context):
+def format_and_lint(context: Context) -> None:
format_all(context)
lint(context)
@@ -209,14 +208,14 @@ def format_and_lint(context: Context):
@task
-def generate(context: Context):
+def generate(context: Context) -> None:
"""Generate internal backend models."""
_generate_schemas(context=context)
_generate_protocols(context=context)
@task
-def validate_generated(context: Context, docker: bool = False):
+def validate_generated(context: Context, docker: bool = False) -> None:
"""Validate that the generated documentation is committed to Git."""
_generate_schemas(context=context)
@@ -230,7 +229,7 @@ def validate_generated(context: Context, docker: bool = False):
context.run(exec_cmd)
-def _generate_schemas(context: Context):
+def _generate_schemas(context: Context) -> None:
from jinja2 import Environment, FileSystemLoader, StrictUndefined
from infrahub.core.schema.definitions.internal import (
@@ -321,7 +320,7 @@ def _sort_and_filter_models(
return sorted(filtered, key=lambda k: (k["namespace"].lower(), k["name"].lower()))
-def _generate_protocols(context: Context):
+def _generate_protocols(context: Context) -> None:
from jinja2 import Environment, FileSystemLoader, StrictUndefined
from infrahub.core.schema.definitions.core import core_models
diff --git a/tasks/container_ops.py b/tasks/container_ops.py
index 859231a1ec..5f46412ba0 100644
--- a/tasks/container_ops.py
+++ b/tasks/container_ops.py
@@ -3,7 +3,17 @@
import sys
from typing import TYPE_CHECKING, Optional
-from .shared import AVAILABLE_SERVICES, BUILD_NAME, build_compose_files_cmd, execute_command, get_env_vars
+from .shared import (
+ AVAILABLE_SERVICES,
+ BUILD_NAME,
+ SERVICE_SERVER_NAME,
+ SERVICE_WORKER_NAME,
+ Namespace,
+ build_compose_files_cmd,
+ execute_command,
+ get_compose_cmd,
+ get_env_vars,
+)
from .utils import ESCAPED_REPO_PATH
if TYPE_CHECKING:
@@ -15,7 +25,7 @@ def build_images(
python_ver: str,
nocache: bool,
database: str,
- namespace: str,
+ namespace: Namespace,
service: Optional[str] = None,
) -> None:
if service and service not in AVAILABLE_SERVICES:
@@ -25,7 +35,8 @@ def build_images(
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- base_cmd = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ base_cmd = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
print(f"base_cmd={base_cmd}")
exec_cmd = f"build --build-arg PYTHON_VER={python_ver}"
print(f"exec_cmd={exec_cmd}")
@@ -41,74 +52,78 @@ def build_images(
def destroy_environment(
context: Context,
database: str,
- namespace: str,
+ namespace: Namespace,
) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
-
- command = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} down --remove-orphans --volumes --timeout 1"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ command = f"{get_env_vars(context)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME} down --remove-orphans --volumes --timeout 1"
execute_command(context=context, command=command)
-def pull_images(context: Context, database: str, namespace: str) -> None:
+def pull_images(context: Context, database: str, namespace: Namespace) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
-
+ compose_cmd = get_compose_cmd(namespace=namespace)
for service in AVAILABLE_SERVICES:
- if "infrahub" in service:
+ if service in [SERVICE_SERVER_NAME, SERVICE_WORKER_NAME]:
continue
- command = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME} pull {service}"
+ command = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME} pull {service}"
execute_command(context=context, command=command)
-def restart_services(context: Context, database: str, namespace: str) -> None:
+def restart_services(context: Context, database: str, namespace: Namespace) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- base_cmd = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ base_cmd = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
- execute_command(context=context, command=f"{base_cmd} restart infrahub-server")
- execute_command(context=context, command=f"{base_cmd} restart infrahub-git")
+ execute_command(context=context, command=f"{base_cmd} restart {SERVICE_SERVER_NAME}")
+ execute_command(context=context, command=f"{base_cmd} restart {SERVICE_WORKER_NAME}")
-def show_service_status(context: Context, database: str, namespace: str) -> None:
+def show_service_status(context: Context, database: str, namespace: Namespace) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- command = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME} ps"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ command = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME} ps"
execute_command(context=context, command=command)
-def start_services(context: Context, database: str, namespace: str, wait: bool) -> None:
+def start_services(context: Context, database: str, namespace: Namespace, wait: bool) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
+ compose_cmd = get_compose_cmd(namespace=namespace)
should_wait = " --wait" if wait else ""
- command = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME} up -d{should_wait}"
+ command = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME} up -d{should_wait}"
execute_command(context=context, command=command)
-def stop_services(context: Context, database: str, namespace: str) -> None:
+def stop_services(context: Context, database: str, namespace: Namespace) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- command = (
- f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME} down"
- )
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ command = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME} down"
execute_command(context=context, command=command)
-def migrate_database(context: Context, database: str, namespace: str) -> None:
+def migrate_database(context: Context, database: str, namespace: Namespace) -> None:
"""Apply the latest database migrations."""
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- base_cmd = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
- command = f"{base_cmd} run infrahub-server infrahub db migrate"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ base_cmd = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
+ command = f"{base_cmd} run {SERVICE_SERVER_NAME} infrahub db migrate"
execute_command(context=context, command=command)
-def update_core_schema(context: Context, database: str, namespace: str, debug: bool = False) -> None:
+def update_core_schema(context: Context, database: str, namespace: Namespace, debug: bool = False) -> None:
"""Update the core schema."""
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- base_cmd = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
- command = f"{base_cmd} run infrahub-server infrahub db update-core-schema"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ base_cmd = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
+ command = f"{base_cmd} run {SERVICE_SERVER_NAME} infrahub db update-core-schema"
if debug:
command += " --debug"
execute_command(context=context, command=command)
diff --git a/tasks/demo.py b/tasks/demo.py
index 94231b2337..efb5cdd800 100644
--- a/tasks/demo.py
+++ b/tasks/demo.py
@@ -21,13 +21,17 @@
BUILD_NAME,
INFRAHUB_DATABASE,
PYTHON_VER,
+ SERVICE_SERVER_NAME,
+ Namespace,
build_compose_files_cmd,
execute_command,
get_env_vars,
)
from .utils import ESCAPED_REPO_PATH
-NAMESPACE = "DEMO"
+NAMESPACE = Namespace.DEFAULT
+
+SERVICE_WORKER_NAME = "infrahub-git"
@task(optional=["database"])
@@ -37,7 +41,7 @@ def build(
python_ver: str = PYTHON_VER,
nocache: bool = False,
database: str = INFRAHUB_DATABASE,
-):
+) -> None:
"""Build an image with the provided name and python version.
Args:
@@ -51,7 +55,7 @@ def build(
@task(optional=["database"])
-def pull(context: Context, database: str = INFRAHUB_DATABASE):
+def pull(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Pull external containers from registry."""
pull_images(context=context, database=database, namespace=NAMESPACE)
@@ -62,68 +66,72 @@ def pull(context: Context, database: str = INFRAHUB_DATABASE):
@task(optional=["database"])
-def start(context: Context, database: str = INFRAHUB_DATABASE, wait: bool = False):
+def start(context: Context, database: str = INFRAHUB_DATABASE, wait: bool = False) -> None:
"""Start a local instance of Infrahub within docker compose."""
start_services(context=context, database=database, namespace=NAMESPACE, wait=wait)
@task(optional=["database"])
-def restart(context: Context, database: str = INFRAHUB_DATABASE):
+def restart(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Restart Infrahub API Server and Git Agent within docker compose."""
restart_services(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def stop(context: Context, database: str = INFRAHUB_DATABASE):
+def stop(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Stop the running instance of Infrahub."""
stop_services(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def destroy(context: Context, database: str = INFRAHUB_DATABASE):
+def destroy(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Destroy all containers and volumes."""
destroy_environment(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def migrate(context: Context, database: str = INFRAHUB_DATABASE):
+def migrate(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Apply the latest database migrations."""
migrate_database(context=context, database=database, namespace=NAMESPACE)
update_core_schema(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def cli_server(context: Context, database: str = INFRAHUB_DATABASE):
+def cli_server(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Launch a bash shell inside the running Infrahub container."""
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database)
- command = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run infrahub-server bash"
+ command = (
+ f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {SERVICE_SERVER_NAME} bash"
+ )
execute_command(context=context, command=command)
@task(optional=["database"])
-def cli_git(context: Context, database: str = INFRAHUB_DATABASE):
+def cli_git(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Launch a bash shell inside the running Infrahub container."""
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database)
- command = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run infrahub-git bash"
+ command = (
+ f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {SERVICE_WORKER_NAME} bash"
+ )
execute_command(context=context, command=command)
@task(optional=["database"])
-def status(context: Context, database: str = INFRAHUB_DATABASE):
+def status(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Display the status of all containers."""
show_service_status(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def load_infra_schema(context: Context, database: str = INFRAHUB_DATABASE):
+def load_infra_schema(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Load the base schema for infrastructure."""
load_infrastructure_schema(context=context, database=database, namespace=NAMESPACE, add_wait=False)
restart_services(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def load_infra_data(context: Context, database: str = INFRAHUB_DATABASE):
+def load_infra_data(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Load infrastructure demo data."""
load_infrastructure_data(context=context, database=database, namespace=NAMESPACE)
diff --git a/tasks/dev.py b/tasks/dev.py
index 94f76b94af..71fe3ad74d 100644
--- a/tasks/dev.py
+++ b/tasks/dev.py
@@ -23,9 +23,12 @@
BUILD_NAME,
INFRAHUB_DATABASE,
PYTHON_VER,
+ SERVICE_WORKER_NAME,
+ Namespace,
build_compose_files_cmd,
build_dev_compose_files_cmd,
execute_command,
+ get_compose_cmd,
get_env_vars,
)
from .utils import ESCAPED_REPO_PATH
@@ -34,7 +37,7 @@
from invoke.context import Context
-NAMESPACE = "DEV"
+NAMESPACE = Namespace.DEV
@task(optional=["database"])
@@ -44,7 +47,7 @@ def build(
python_ver: str = PYTHON_VER,
nocache: bool = False,
database: str = INFRAHUB_DATABASE,
-):
+) -> None:
"""Build an image with the provided name and python version.
Args:
@@ -58,27 +61,29 @@ def build(
@task(optional=["database"])
-def debug(context: Context, database: str = INFRAHUB_DATABASE):
+def debug(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Start a local instance of Infrahub in debug mode."""
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database)
- command = f"{get_env_vars(context, namespace=NAMESPACE)} docker compose {compose_files_cmd} -p {BUILD_NAME} up"
+ compose_cmd = get_compose_cmd(namespace=NAMESPACE)
+ command = f"{get_env_vars(context, namespace=NAMESPACE)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME} up"
execute_command(context=context, command=command)
@task(optional=["database"])
-def deps(context: Context, database: str = INFRAHUB_DATABASE):
+def deps(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Start local instances of dependencies (Databases and Message Bus)."""
with context.cd(ESCAPED_REPO_PATH):
dev_compose_files_cmd = build_dev_compose_files_cmd(database=database)
+ compose_cmd = get_compose_cmd(namespace=NAMESPACE)
command = (
- f"{get_env_vars(context, namespace=NAMESPACE)} docker compose {dev_compose_files_cmd} -p {BUILD_NAME} up -d"
+ f"{get_env_vars(context, namespace=NAMESPACE)} {compose_cmd} {dev_compose_files_cmd} -p {BUILD_NAME} up -d"
)
execute_command(context=context, command=command)
@task
-def destroy(context: Context, database: str = INFRAHUB_DATABASE):
+def destroy(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Destroy all containers and volumes."""
destroy_environment(context=context, database=database, namespace=NAMESPACE)
@@ -87,89 +92,91 @@ def destroy(context: Context, database: str = INFRAHUB_DATABASE):
def infra_git_create(
context: Context,
database: str = INFRAHUB_DATABASE,
- name="demo-edge",
- location="/remote/infrahub-demo-edge",
-):
+ name: str = "demo-edge",
+ location: str = "/remote/infrahub-demo-edge",
+) -> None:
"""Load some demo data."""
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=NAMESPACE)
- base_cmd = f"{get_env_vars(context, namespace=NAMESPACE)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
+ compose_cmd = get_compose_cmd(namespace=NAMESPACE)
+ base_cmd = f"{get_env_vars(context, namespace=NAMESPACE)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
execute_command(
context=context,
- command=f"{base_cmd} run infrahub-git infrahubctl repository add {name} {location}",
+ command=f"{base_cmd} run {SERVICE_WORKER_NAME} infrahubctl repository add {name} {location}",
)
@task(optional=["database"])
-def infra_git_import(context: Context, database: str = INFRAHUB_DATABASE):
+def infra_git_import(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Load some demo data."""
REPO_NAME = "infrahub-demo-edge"
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=NAMESPACE)
- base_cmd = f"{get_env_vars(context, namespace=NAMESPACE)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
+ compose_cmd = get_compose_cmd(namespace=NAMESPACE)
+ base_cmd = f"{get_env_vars(context, namespace=NAMESPACE)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
execute_command(
context=context,
- command=f"{base_cmd} run infrahub-git cp -r backend/tests/fixtures/repos/{REPO_NAME}/initial__main /remote/{REPO_NAME}",
+ command=f"{base_cmd} run {SERVICE_WORKER_NAME} cp -r backend/tests/fixtures/repos/{REPO_NAME}/initial__main /remote/{REPO_NAME}",
)
execute_command(
context=context,
- command=f"{base_cmd} exec --workdir /remote/{REPO_NAME} infrahub-git git init --initial-branch main",
+ command=f"{base_cmd} exec --workdir /remote/{REPO_NAME} {SERVICE_WORKER_NAME} git init --initial-branch main",
)
execute_command(
context=context,
- command=f"{base_cmd} exec --workdir /remote/{REPO_NAME} infrahub-git git add .",
+ command=f"{base_cmd} exec --workdir /remote/{REPO_NAME} {SERVICE_WORKER_NAME} git add .",
)
execute_command(
context=context,
- command=f"{base_cmd} exec --workdir /remote/{REPO_NAME} infrahub-git git commit -m first",
+ command=f"{base_cmd} exec --workdir /remote/{REPO_NAME} {SERVICE_WORKER_NAME} git commit -m first",
)
@task(optional=["database"])
-def load_infra_data(context: Context, database: str = INFRAHUB_DATABASE):
+def load_infra_data(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Load infrastructure demo data."""
load_infrastructure_data(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def load_infra_schema(context: Context, database: str = INFRAHUB_DATABASE):
+def load_infra_schema(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Load the base schema for infrastructure."""
load_infrastructure_schema(context=context, database=database, namespace=NAMESPACE, add_wait=False)
restart_services(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def pull(context: Context, database: str = INFRAHUB_DATABASE):
+def pull(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Pull external containers from registry."""
pull_images(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def restart(context: Context, database: str = INFRAHUB_DATABASE):
+def restart(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Restart Infrahub API Server and Git Agent within docker compose."""
restart_services(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def status(context: Context, database: str = INFRAHUB_DATABASE):
+def status(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Display the status of all containers."""
show_service_status(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def start(context: Context, database: str = INFRAHUB_DATABASE, wait: bool = False):
+def start(context: Context, database: str = INFRAHUB_DATABASE, wait: bool = False) -> None:
"""Start a local instance of Infrahub within docker compose."""
start_services(context=context, database=database, namespace=NAMESPACE, wait=wait)
@task(optional=["database"])
-def stop(context: Context, database: str = INFRAHUB_DATABASE):
+def stop(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Stop the running instance of Infrahub."""
stop_services(context=context, database=database, namespace=NAMESPACE)
@task(optional=["database"])
-def migrate(context: Context, database: str = INFRAHUB_DATABASE):
+def migrate(context: Context, database: str = INFRAHUB_DATABASE) -> None:
"""Apply the latest database migrations."""
migrate_database(context=context, database=database, namespace=NAMESPACE)
update_core_schema(context=context, database=database, namespace=NAMESPACE, debug=True)
@@ -183,12 +190,12 @@ def get_version_from_pyproject() -> str:
@task
-def update_helm_chart(context, chart_file: Optional[str] = "helm/Chart.yaml"):
+def update_helm_chart(context: Context, chart_file: Optional[str] = "helm/Chart.yaml") -> None:
"""Update helm/Chart.yaml with the current version from pyproject.toml."""
version = get_version_from_pyproject()
version_pattern = r"^appVersion:\s*[\d\.\-a-zA-Z]+"
- def replace_version(match):
+ def replace_version(match: str) -> str:
return f"appVersion: {version}"
chart_path = Path(chart_file)
@@ -201,12 +208,12 @@ def replace_version(match):
@task
-def update_docker_compose(context, docker_file: Optional[str] = "docker-compose.yml"):
+def update_docker_compose(context: Context, docker_file: Optional[str] = "docker-compose.yml") -> None:
"""Update docker-compose.yml with the current version from pyproject.toml."""
version = get_version_from_pyproject()
version_pattern = r"registry.opsmill.io/opsmill/infrahub:\$\{VERSION:-[\d\.\-a-zA-Z]+\}"
- def replace_version(match):
+ def replace_version(match: str) -> str:
return f"registry.opsmill.io/opsmill/infrahub:${{VERSION:-{version}}}"
docker_path = Path(docker_file)
@@ -217,7 +224,7 @@ def replace_version(match):
print(f"{docker_file} updated with version {version}")
-def get_enum_mappings():
+def get_enum_mappings() -> dict:
"""Extracts enum mappings dynamically."""
from infrahub.config import BrokerDriver, CacheDriver, StorageDriver, TraceExporterType, TraceTransportProtocol
from infrahub.database.constants import DatabaseType
@@ -310,7 +317,7 @@ def update_docker_compose_env_vars(
@task
def gen_config_env(
context: Context, docker_file: Optional[str] = "docker-compose.yml", update_docker_file: Optional[bool] = False
-):
+) -> None:
"""Generate list of env vars required for configuration and update docker file.yml if need be."""
from pydantic_settings import BaseSettings
from pydantic_settings.sources import EnvSettingsSource
@@ -330,7 +337,7 @@ def gen_config_env(
settings = Settings()
env_defaults = {}
- def fetch_fields(subset: BaseSettings):
+ def fetch_fields(subset: BaseSettings) -> None:
env_settings = EnvSettingsSource(
subset.__class__,
env_prefix=subset.model_config.get("env_prefix"),
@@ -348,8 +355,7 @@ def fetch_fields(subset: BaseSettings):
subsettings = getattr(settings, subsetting)
fetch_fields(subsettings)
- if "PATH" in env_vars:
- env_vars.remove("PATH")
+ env_vars.discard("PATH")
if update_docker_file:
update_docker_compose_env_vars(
env_vars=sorted(env_vars), env_defaults=env_defaults, enum_mappings=enum_mappings, docker_file=docker_file
diff --git a/tasks/docs.py b/tasks/docs.py
index 6082a5e3e6..29ab2fc5e9 100644
--- a/tasks/docs.py
+++ b/tasks/docs.py
@@ -19,7 +19,7 @@
@task
-def build(context: Context):
+def build(context: Context) -> None:
"""Build documentation website."""
exec_cmd = "npm run build"
@@ -31,55 +31,49 @@ def build(context: Context):
@task
-def generate(context: Context):
+def generate(context: Context) -> None:
"""Generate all documentation output from code."""
_generate(context=context)
@task
-def generate_schema(context: Context):
+def generate_schema(context: Context) -> None:
"""Generate documentation for the schema."""
_generate_infrahub_schema_documentation()
@task
-def generate_infrahub_cli(context: Context):
+def generate_infrahub_cli(context: Context) -> None:
"""Generate documentation for the infrahub cli."""
_generate_infrahub_cli_documentation(context=context)
@task
-def generate_infrahubctl(context: Context):
+def generate_infrahubctl(context: Context) -> None:
"""Generate documentation for the infrahubctl cli."""
_generate_infrahubctl_documentation(context=context)
@task
-def generate_infrahubsync_sync(context: Context):
- """Generate documentation for the infrahub-sync cli."""
- _generate_infrahubsync_documentation(context=context)
-
-
-@task
-def generate_repository(context: Context):
+def generate_repository(context: Context) -> None:
"""Generate documentation for the repository configuration file."""
_generate_infrahub_repository_configuration_documentation(context=context)
@task
-def generate_python_sdk(context: Context):
+def generate_python_sdk(context: Context) -> None:
"""Generate documentation for the Python SDK."""
_generate_infrahub_sdk_configuration_documentation(context=context)
@task
-def generate_bus_events(context: Context):
+def generate_bus_events(context: Context) -> None:
"""Generate documentation for the Bus events."""
_generate_infrahub_events_documentation(context=context)
@task
-def install(context: Context):
+def install(context: Context) -> None:
"""Install documentation dependencies."""
exec_cmd = "npm install"
@@ -91,7 +85,7 @@ def install(context: Context):
@task
-def validate(context: Context, docker: bool = False):
+def validate(context: Context, docker: bool = False) -> None:
"""Validate that the generated documentation is committed to Git."""
if docker:
@@ -109,7 +103,7 @@ def validate(context: Context, docker: bool = False):
@task
-def serve(context: Context):
+def serve(context: Context) -> None:
"""Run documentation server in development mode."""
exec_cmd = "npm run serve"
@@ -119,7 +113,7 @@ def serve(context: Context):
@task
-def vale(context: Context):
+def vale(context: Context) -> None:
"""Run vale to validate the documentation."""
has_vale = check_if_command_available(context=context, command_name="vale")
@@ -134,7 +128,7 @@ def vale(context: Context):
@task
-def markdownlint(context: Context):
+def markdownlint(context: Context) -> None:
has_markdownlint = check_if_command_available(context=context, command_name="markdownlint-cli2")
if not has_markdownlint:
@@ -147,7 +141,7 @@ def markdownlint(context: Context):
@task
-def format_markdownlint(context: Context):
+def format_markdownlint(context: Context) -> None:
"""Run markdownlint-cli2 to format all .md/mdx files."""
print(" - [docs] Format code with markdownlint-cli2")
@@ -157,19 +151,19 @@ def format_markdownlint(context: Context):
@task
-def format(context: Context):
+def format(context: Context) -> None:
"""This will run all formatter."""
format_markdownlint(context)
@task
-def lint(context: Context):
+def lint(context: Context) -> None:
"""This will run all linter."""
markdownlint(context)
vale(context)
-def _generate_infrahub_cli_documentation(context: Context):
+def _generate_infrahub_cli_documentation(context: Context) -> None:
"""Generate the documentation for infrahub cli using typer-cli."""
CLI_COMMANDS = (
@@ -185,10 +179,9 @@ def _generate_infrahub_cli_documentation(context: Context):
context.run(exec_cmd)
-def _generate(context: Context):
+def _generate(context: Context) -> None:
"""Generate documentation output from code."""
_generate_infrahub_cli_documentation(context=context)
- # _generate_infrahubsync_documentation(context=context)
_generate_infrahubctl_documentation(context=context)
_generate_infrahub_schema_documentation()
_generate_infrahub_repository_configuration_documentation()
@@ -196,7 +189,7 @@ def _generate(context: Context):
_generate_infrahub_events_documentation()
-def _generate_infrahubctl_documentation(context: Context):
+def _generate_infrahubctl_documentation(context: Context) -> None:
"""Generate the documentation for infrahubctl using typer-cli."""
from infrahub_sdk.ctl.cli import app
@@ -214,16 +207,6 @@ def _generate_infrahubctl_documentation(context: Context):
context.run(exec_cmd)
-def _generate_infrahubsync_documentation(context: Context):
- """Generate the documentation for infrahub-sync using typer-cli."""
-
- print(" - Generate infrahub-sync CLI documentation")
- exec_cmd = 'poetry run typer infrahub_sync.cli utils docs --name "infrahub-sync"'
- exec_cmd += " --output docs/docs/integrations/sync/reference/cli.mdx"
- with context.cd(ESCAPED_REPO_PATH):
- context.run(exec_cmd)
-
-
def _generate_infrahub_schema_documentation() -> None:
"""Generate documentation for the schema"""
import jinja2
@@ -347,9 +330,7 @@ def _generate_infrahub_repository_configuration_documentation() -> None:
for name, definition in schema["$defs"].items():
for property, value in definition["properties"].items():
- definitions[name]["properties"][property]["required"] = (
- True if property in definition["required"] else False
- )
+ definitions[name]["properties"][property]["required"] = property in definition["required"]
if "anyOf" in value:
definitions[name]["properties"][property]["type"] = ", ".join(
[i["type"] for i in value["anyOf"] if i["type"] != "null"]
diff --git a/tasks/infra_ops.py b/tasks/infra_ops.py
index fe6c977ff9..cdaac7f186 100644
--- a/tasks/infra_ops.py
+++ b/tasks/infra_ops.py
@@ -2,28 +2,38 @@
from typing import TYPE_CHECKING
-from .shared import BUILD_NAME, build_compose_files_cmd, execute_command, get_env_vars
+from .shared import (
+ BUILD_NAME,
+ SERVICE_WORKER_NAME,
+ Namespace,
+ build_compose_files_cmd,
+ execute_command,
+ get_compose_cmd,
+ get_env_vars,
+)
from .utils import ESCAPED_REPO_PATH
if TYPE_CHECKING:
from invoke.context import Context
-def load_infrastructure_data(context: Context, database: str, namespace: str) -> None:
+def load_infrastructure_data(context: Context, database: str, namespace: Namespace) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- base_cmd = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
- command = f"{base_cmd} run infrahub-git infrahubctl run models/infrastructure_edge.py"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ base_cmd = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
+ command = f"{base_cmd} run {SERVICE_WORKER_NAME} infrahubctl run models/infrastructure_edge.py"
execute_command(context=context, command=command)
def load_infrastructure_schema(
- context: Context, database: str, namespace: str, add_wait: bool = True, target: str = "models/base"
+ context: Context, database: str, namespace: Namespace, add_wait: bool = True, target: str = "models/base"
) -> None:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_compose_files_cmd(database=database, namespace=namespace)
- base_cmd = f"{get_env_vars(context, namespace=namespace)} docker compose {compose_files_cmd} -p {BUILD_NAME}"
- command = f"{base_cmd} run infrahub-git infrahubctl schema load {target}"
+ compose_cmd = get_compose_cmd(namespace=namespace)
+ base_cmd = f"{get_env_vars(context, namespace=namespace)} {compose_cmd} {compose_files_cmd} -p {BUILD_NAME}"
+ command = f"{base_cmd} run {SERVICE_WORKER_NAME} infrahubctl schema load {target}"
if add_wait:
command += " --wait 30"
execute_command(context=context, command=command)
diff --git a/tasks/main.py b/tasks/main.py
index e950c486c4..50788729f8 100644
--- a/tasks/main.py
+++ b/tasks/main.py
@@ -11,7 +11,7 @@
# ----------------------------------------------------------------------------
-def _format_ruff(context: Context):
+def _format_ruff(context: Context) -> None:
"""Run ruff to format all Python files."""
print(f" - [{NAMESPACE}] Format code with ruff")
@@ -22,7 +22,7 @@ def _format_ruff(context: Context):
@task(name="format", default=True)
-def format_all(context: Context):
+def format_all(context: Context) -> None:
"""This will run all formatters."""
_format_ruff(context)
diff --git a/tasks/performance.py b/tasks/performance.py
index 5252eb9ed0..0f254aca0a 100644
--- a/tasks/performance.py
+++ b/tasks/performance.py
@@ -7,7 +7,7 @@
@task
-def run(context: Context, directory: str = "utilities", dataset: str = "dataset03"):
+def run(context: Context, directory: str = "utilities", dataset: str = "dataset03") -> None:
"""Launch a performance test using Locust. Gunicorn must be running"""
PERFORMANCE_FILE_PREFIX = "locust_"
NOW = datetime.now(tz=timezone.utc)
diff --git a/tasks/schema.py b/tasks/schema.py
index d5a73489a8..8c318a1de9 100644
--- a/tasks/schema.py
+++ b/tasks/schema.py
@@ -11,14 +11,14 @@
@task
-def generate_jsonschema(context: Context):
+def generate_jsonschema(context: Context) -> None:
"""Generate JSON schemas into ./generated"""
generate_sdk_repository_config()
generate_infrahub_node_schema()
-def generate_infrahub_node_schema():
+def generate_infrahub_node_schema() -> None:
from infrahub.api.schema import SchemaLoadAPI
schema_dir = Path(f"{INFRAHUB_DIRECTORY}/schema")
@@ -33,7 +33,7 @@ def generate_infrahub_node_schema():
write(file_path=schema_dir / "develop.json", content=content)
-def generate_sdk_repository_config():
+def generate_sdk_repository_config() -> None:
from infrahub_sdk.schema import InfrahubRepositoryConfig
repository_dir = Path(f"{SDK_DIRECTORY}/repository-config")
diff --git a/tasks/sdk.py b/tasks/sdk.py
index bb606a3e73..6784c01fe5 100644
--- a/tasks/sdk.py
+++ b/tasks/sdk.py
@@ -1,6 +1,8 @@
import os
+from typing import Optional
from invoke import Context, task
+from invoke.runners import Result
from .shared import (
BUILD_NAME,
@@ -23,7 +25,7 @@
# ----------------------------------------------------------------------------
-def _format_ruff(context: Context):
+def _format_ruff(context: Context) -> None:
"""Run ruff to format all Python files."""
print(f" - [{NAMESPACE}] Format code with ruff")
@@ -34,7 +36,7 @@ def _format_ruff(context: Context):
@task(name="format")
-def format_all(context: Context):
+def format_all(context: Context) -> None:
"""This will run all formatter."""
_format_ruff(context)
@@ -46,7 +48,7 @@ def format_all(context: Context):
# Testing tasks
# ----------------------------------------------------------------------------
@task
-def ruff(context: Context, docker: bool = False):
+def ruff(context: Context, docker: bool = False) -> None:
"""Run ruff to check that Python files adherence to black standards."""
print(f" - [{NAMESPACE}] Check code with ruff")
@@ -69,7 +71,7 @@ def ruff(context: Context, docker: bool = False):
@task
-def mypy(context: Context, docker: bool = False):
+def mypy(context: Context, docker: bool = False) -> None:
"""This will run mypy for the specified name and Python version."""
print(f" - [{NAMESPACE}] Check code with mypy")
@@ -90,7 +92,7 @@ def mypy(context: Context, docker: bool = False):
@task
-def pylint(context: Context, docker: bool = False):
+def pylint(context: Context, docker: bool = False) -> None:
"""This will run pylint for the specified name and Python version."""
print(f" - [{NAMESPACE}] Check code with pylint")
@@ -111,7 +113,7 @@ def pylint(context: Context, docker: bool = False):
@task
-def lint(context: Context, docker: bool = False):
+def lint(context: Context, docker: bool = False) -> Optional[Result]:
"""This will run all linter."""
ruff(context, docker=docker)
mypy(context, docker=docker)
@@ -121,7 +123,7 @@ def lint(context: Context, docker: bool = False):
@task
-def test_unit(context: Context):
+def test_unit(context: Context) -> Optional[Result]:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_test_compose_files_cmd(database=False)
base_cmd = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {build_test_envs()} infrahub-test"
@@ -131,7 +133,7 @@ def test_unit(context: Context):
@task(optional=["database"])
-def test_integration(context: Context, database: str = INFRAHUB_DATABASE):
+def test_integration(context: Context, database: str = INFRAHUB_DATABASE) -> Optional[Result]:
with context.cd(ESCAPED_REPO_PATH):
compose_files_cmd = build_test_compose_files_cmd(database=database)
base_cmd = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {build_test_envs()} infrahub-test"
@@ -141,6 +143,6 @@ def test_integration(context: Context, database: str = INFRAHUB_DATABASE):
@task(default=True)
-def format_and_lint(context: Context):
+def format_and_lint(context: Context) -> None:
format_all(context)
lint(context)
diff --git a/tasks/shared.py b/tasks/shared.py
index c0fd2d583a..98c4fce1cd 100644
--- a/tasks/shared.py
+++ b/tasks/shared.py
@@ -17,6 +17,12 @@ class DatabaseType(str, Enum):
MEMGRAPH = "memgraph"
+class Namespace(str, Enum):
+ DEFAULT = "default" # aka demo
+ DEV = "dev"
+ TEST = "test"
+
+
INVOKE_SUDO = os.getenv("INVOKE_SUDO", None)
INVOKE_PTY = os.getenv("INVOKE_PTY", None)
INFRAHUB_DATABASE = os.getenv("INFRAHUB_DB_TYPE", DatabaseType.NEO4J.value)
@@ -26,12 +32,14 @@ class DatabaseType(str, Enum):
DATABASE_DOCKER_IMAGE = os.getenv("DATABASE_DOCKER_IMAGE", None)
MEMGRAPH_DOCKER_IMAGE = os.getenv("MEMGRAPH_DOCKER_IMAGE", "memgraph/memgraph-mage:1.19-memgraph-2.19-no-ml")
-NEO4J_DOCKER_IMAGE = os.getenv("NEO4J_DOCKER_IMAGE", "neo4j:5.19.0-enterprise")
+NEO4J_DOCKER_IMAGE = os.getenv("NEO4J_DOCKER_IMAGE", "neo4j:5.20.0-enterprise")
MESSAGE_QUEUE_DOCKER_IMAGE = os.getenv(
"MESSAGE_QUEUE_DOCKER_IMAGE", "rabbitmq:3.13.7-management" if not INFRAHUB_USE_NATS else "nats:2.10.14-alpine"
)
CACHE_DOCKER_IMAGE = os.getenv("CACHE_DOCKER_IMAGE", "redis:7.2.4" if not INFRAHUB_USE_NATS else "nats:2.10.14-alpine")
+TASK_MANAGER_DOCKER_IMAGE = os.getenv("TASK_MANAGER_DOCKER_IMAGE", "prefecthq/prefect:3.0.3-python3.12")
+
here = Path(__file__).parent.resolve()
TOP_DIRECTORY_NAME = here.parent.name
BUILD_NAME = os.getenv("INFRAHUB_BUILD_NAME", re.sub(r"[^a-zA-Z0-9_/.]", "", str(TOP_DIRECTORY_NAME)))
@@ -42,7 +50,11 @@ class DatabaseType(str, Enum):
NBR_WORKERS = os.getenv("PYTEST_XDIST_WORKER_COUNT", 1)
GITHUB_ACTION = os.getenv("GITHUB_ACTION", False)
-AVAILABLE_SERVICES = ["infrahub-git", "infrahub-server", "database", "message-queue"]
+
+SERVICE_SERVER_NAME = "server"
+SERVICE_WORKER_NAME = "task-worker"
+AVAILABLE_SERVICES = [SERVICE_SERVER_NAME, SERVICE_WORKER_NAME, "database", "message-queue", "task-manager", "cache"]
+
SUPPORTED_DATABASES = [DatabaseType.MEMGRAPH.value, DatabaseType.NEO4J.value]
COMPOSE_FILES_DEPS = {False: "development/docker-compose-deps.yml", True: "development/docker-compose-deps-nats.yml"}
@@ -51,15 +63,13 @@ class DatabaseType(str, Enum):
TEST_COMPOSE_FILES_MEMGRAPH = [
COMPOSE_FILES_DEPS[INFRAHUB_USE_NATS],
"development/docker-compose-test-database-memgraph.yml",
- "development/docker-compose-test-cache.yml",
- "development/docker-compose-test-message-queue.yml",
+ "development/docker-compose-test-deps.yml",
TEST_COMPOSE_FILE,
]
TEST_COMPOSE_FILES_NEO4J = [
COMPOSE_FILES_DEPS[INFRAHUB_USE_NATS],
"development/docker-compose-test-database-neo4j.yml",
- "development/docker-compose-test-cache.yml",
- "development/docker-compose-test-message-queue.yml",
+ "development/docker-compose-test-deps.yml",
TEST_COMPOSE_FILE,
]
@@ -117,6 +127,8 @@ class DatabaseType(str, Enum):
"database_logs",
"git_data",
"git_remote_data",
+ "workflow_data",
+ "workflow_db",
"storage_data",
]
@@ -176,6 +188,29 @@ def check_environment(context: Context) -> dict:
return params
+def dumb_terminal() -> bool:
+ return os.getenv("TERM", "").lower() == "dumb"
+
+
+def get_compose_cmd(namespace: Namespace) -> str:
+ options = []
+
+ if namespace == Namespace.DEV:
+ options.append("--profile dev")
+ elif namespace == Namespace.DEFAULT:
+ options.append("--profile demo")
+ elif namespace == Namespace.TEST:
+ options.append("--profile test")
+
+ if dumb_terminal():
+ options.append("--ansi never")
+
+ if len(options) > 0:
+ return f"docker compose {' '.join(options)}"
+
+ return "docker compose"
+
+
def execute_command(context: Context, command: str, print_cmd: bool = False) -> Optional[Result]:
params = check_environment(context=context)
@@ -189,7 +224,7 @@ def execute_command(context: Context, command: str, print_cmd: bool = False) ->
return context.run(command, pty=params["pty"])
-def get_env_vars(context: Context, namespace: str = "default") -> str:
+def get_env_vars(context: Context, namespace: Namespace = Namespace.DEFAULT) -> str:
ENV_VARS_DICT = {
"IMAGE_NAME": IMAGE_NAME,
"IMAGE_VER": IMAGE_VER,
@@ -198,10 +233,11 @@ def get_env_vars(context: Context, namespace: str = "default") -> str:
"NBR_WORKERS": NBR_WORKERS,
"CACHE_DOCKER_IMAGE": CACHE_DOCKER_IMAGE,
"MESSAGE_QUEUE_DOCKER_IMAGE": MESSAGE_QUEUE_DOCKER_IMAGE,
+ "TASK_MANAGER_DOCKER_IMAGE": TASK_MANAGER_DOCKER_IMAGE,
"INFRAHUB_DB_TYPE": INFRAHUB_DATABASE,
}
- if namespace == "DEV" and not REQUESTED_IMAGE_VER:
+ if namespace == Namespace.DEV and not REQUESTED_IMAGE_VER:
ENV_VARS_DICT["IMAGE_VER"] = "local"
if DATABASE_DOCKER_IMAGE:
@@ -213,7 +249,7 @@ def get_env_vars(context: Context, namespace: str = "default") -> str:
return " ".join([f"{key}={value}" for key, value in ENV_VARS_DICT.items()])
-def build_compose_files_cmd(database: str, namespace: str = "") -> str:
+def build_compose_files_cmd(database: str, namespace: Namespace = Namespace.DEFAULT) -> str:
if database not in SUPPORTED_DATABASES:
sys.exit(f"{database} is not a valid database ({SUPPORTED_DATABASES})")
@@ -228,7 +264,7 @@ def build_compose_files_cmd(database: str, namespace: str = "") -> str:
else:
COMPOSE_FILES.append(DEFAULT_FILE_NAME)
- if "local" in IMAGE_VER or (namespace == "DEV" and not REQUESTED_IMAGE_VER):
+ if "local" in IMAGE_VER or (namespace == Namespace.DEV and not REQUESTED_IMAGE_VER):
COMPOSE_FILES.append(LOCAL_FILE_NAME)
if os.getenv("CI") is not None:
@@ -295,7 +331,7 @@ def build_test_scale_compose_files_cmd(
return f"-f {' -f '.join(TEST_SCALE_COMPOSE_FILES)}"
-def build_test_envs():
+def build_test_envs() -> str:
if GITHUB_ACTION:
return f"-e {' -e '.join(GITHUB_ENVS_TO_PASS)}"
diff --git a/tasks/sync.py b/tasks/sync.py
deleted file mode 100644
index 0858ab67ff..0000000000
--- a/tasks/sync.py
+++ /dev/null
@@ -1,121 +0,0 @@
-from invoke import Context, task
-
-from .shared import (
- BUILD_NAME,
- NBR_WORKERS,
- build_test_compose_files_cmd,
- build_test_envs,
- execute_command,
- get_env_vars,
-)
-from .utils import ESCAPED_REPO_PATH, REPO_BASE
-
-MAIN_DIRECTORY = "sync/infrahub-sync"
-NAMESPACE = "SYNC"
-
-
-# ----------------------------------------------------------------------------
-# Formatting tasks
-# ----------------------------------------------------------------------------
-
-
-def _format_ruff(context: Context):
- """Run ruff to format all Python files."""
-
- print(f" - [{NAMESPACE}] Format code with ruff")
- exec_cmd = f"ruff format {MAIN_DIRECTORY} --config {REPO_BASE}/pyproject.toml && "
- exec_cmd += f"ruff check --fix {MAIN_DIRECTORY} --config {REPO_BASE}/pyproject.toml"
- with context.cd(ESCAPED_REPO_PATH):
- context.run(exec_cmd)
-
-
-@task(name="format")
-def format_all(context: Context):
- """This will run all formatter."""
-
- _format_ruff(context)
-
- print(f" - [{NAMESPACE}] All formatters have been executed!")
-
-
-# ----------------------------------------------------------------------------
-# Testing tasks
-# ----------------------------------------------------------------------------
-@task
-def ruff(context: Context, docker: bool = False):
- """Run ruff to check that Python files adherence to black standards."""
-
- print(f" - [{NAMESPACE}] Check code with ruff")
- exec_cmd = f"ruff check --diff {MAIN_DIRECTORY} --config {REPO_BASE}/pyproject.toml"
-
- if docker:
- compose_files_cmd = build_test_compose_files_cmd(database=False)
- exec_cmd = (
- f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run infrahub-test {exec_cmd}"
- )
- print(exec_cmd)
-
- with context.cd(ESCAPED_REPO_PATH):
- context.run(exec_cmd)
-
-
-@task
-def mypy(context: Context, docker: bool = False):
- """This will run mypy for the specified name and Python version."""
-
- print(f" - [{NAMESPACE}] Check code with mypy")
- exec_cmd = f"mypy --show-error-codes {MAIN_DIRECTORY}"
-
- if docker:
- compose_files_cmd = build_test_compose_files_cmd(database=False)
- exec_cmd = (
- f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run infrahub-test {exec_cmd}"
- )
- print(exec_cmd)
-
- with context.cd(ESCAPED_REPO_PATH):
- context.run(exec_cmd)
-
-
-@task
-def pylint(context: Context, docker: bool = False):
- """This will run pylint for the specified name and Python version."""
-
- print(f" - [{NAMESPACE}] Check code with pylint")
- exec_cmd = f"pylint ./{MAIN_DIRECTORY}/infrahub_sync"
-
- if docker:
- compose_files_cmd = build_test_compose_files_cmd(database=False)
- exec_cmd = (
- f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run infrahub-test {exec_cmd}"
- )
- print(exec_cmd)
-
- with context.cd(ESCAPED_REPO_PATH):
- context.run(exec_cmd)
-
-
-@task
-def lint(context: Context, docker: bool = False):
- """This will run all linter."""
- ruff(context, docker=docker)
- pylint(context, docker=docker)
- # mypy(context, docker=docker)
-
- print(f" - [{NAMESPACE}] All tests have passed!")
-
-
-@task
-def test_unit(context: Context):
- with context.cd(ESCAPED_REPO_PATH):
- compose_files_cmd = build_test_compose_files_cmd(database=False)
- base_cmd = f"{get_env_vars(context)} docker compose {compose_files_cmd} -p {BUILD_NAME} run {build_test_envs()} infrahub-test"
- exec_cmd = f"pytest -n {NBR_WORKERS} -v --cov=infrahub_sync {MAIN_DIRECTORY}/tests/unit"
- print(f"{base_cmd} {exec_cmd}")
- return execute_command(context=context, command=f"{base_cmd} {exec_cmd}")
-
-
-@task(default=True)
-def format_and_lint(context: Context):
- format_all(context)
- lint(context)
diff --git a/utilities/db_backup/__main__.py b/utilities/db_backup/__main__.py
index 760a4a1fdf..a3f81e82df 100644
--- a/utilities/db_backup/__main__.py
+++ b/utilities/db_backup/__main__.py
@@ -5,7 +5,7 @@
from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
-from typing import Dict, Generator, List, Optional
+from typing import Any, Dict, Generator, List, Optional
import docker
from docker.models.containers import Container
@@ -308,7 +308,7 @@ def backup(
class Neo4jRestoreRunner(Neo4jBackupRestoreBase):
backup_helper_container_name = "neo4j-restore-helper"
- def __init__(self, *args, database_cypher_port: int = 7687, **kwargs) -> None:
+ def __init__(self, *args: Any, database_cypher_port: int = 7687, **kwargs: dict[str, Any]) -> None:
super().__init__(*args, **kwargs)
self.database_cypher_port = database_cypher_port
neo4j_auth = os.environ.get("NEO4J_AUTH")
diff --git a/utilities/locust_dataset03_api_response_time.py b/utilities/locust_dataset03_api_response_time.py
index 60cd8e69c6..80a85eef34 100644
--- a/utilities/locust_dataset03_api_response_time.py
+++ b/utilities/locust_dataset03_api_response_time.py
@@ -6,7 +6,7 @@ class InfrahubUser(HttpUser):
# tasks = [InfrahubDataset03]
@task
- def query_device_names(self):
+ def query_device_names(self) -> None:
query = """
query {
device {
@@ -20,7 +20,7 @@ def query_device_names(self):
self.client.post("/graphql", json=data, name="query_device_names")
@task
- def query_one_device(self):
+ def query_one_device(self) -> None:
query = """
query {
device(name__value: "ord1-edge1"){
diff --git a/utilities/proposed_change_faker.py b/utilities/proposed_change_faker.py
index 4a0d3e3672..03f2297540 100644
--- a/utilities/proposed_change_faker.py
+++ b/utilities/proposed_change_faker.py
@@ -168,7 +168,7 @@ async def create_proposed_change(client: InfrahubClient, log: logging.Logger) ->
return new_proposed_change
-async def run(client: InfrahubClient, log: logging.Logger, branch: str):
+async def run(client: InfrahubClient, log: logging.Logger, branch: str) -> None:
proposed_change = await create_proposed_change(client, log)
repository = await create_repository(client, log)
await create_validators(client, log, proposed_change, repository)